Build the backend API that receives documents, calls Claude, and returns structured analysis. By the end, you'll have a working AI endpoint you can call with curl or Postman.
A complete FastAPI backend: document analysis endpoint that calls Claude, structured JSON response with summary, key points, and sentiment, and error handling for all failure modes.
from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel import anthropic, json app = FastAPI() app.add_middleware(CORSMiddleware, allow_origins=["http://localhost:3000"], allow_methods=["*"], allow_headers=["*"]) client = anthropic.Anthropic() class AnalyzeRequest(BaseModel): text: str @app.post("/analyze") def analyze(req: AnalyzeRequest): if not req.text.strip(): raise HTTPException(400, "text is required") msg = client.messages.create( model="claude-sonnet-4-20250514", max_tokens=1024, system="Analyze the provided text. Return JSON only: {summary, key_points: [], sentiment, word_count, reading_time_minutes}", messages=[{"role": "user", "content": req.text}] ) try: return json.loads(msg.content[0].text) except json.JSONDecodeError: return {"summary": msg.content[0].text, "key_points": []}
Start the server: uvicorn main:app --reload
Test with curl:
$ curl -X POST http://localhost:8000/analyze -H "Content-Type: application/json" -d '{"text": "Artificial intelligence is transforming industries worldwide. Companies that adopt AI early gain significant competitive advantages. However, implementation requires careful planning and expertise."}'
Also visit http://localhost:8000/docs and test from the interactive UI. Verify the JSON response has all the expected fields.
JSON parsing tip: Instruct Claude to start its response with an opening brace: add to the system prompt "Start your response with {" — this almost eliminates cases where Claude adds text before the JSON.
Add two more endpoints to make the backend complete:
@app.post("/summarize") def summarize(req: AnalyzeRequest): msg = client.messages.create( model="claude-sonnet-4-20250514", max_tokens=512, system="Summarize in 3 sentences or less. Output only the summary.", messages=[{"role": "user", "content": req.text}] ) return {"summary": msg.content[0].text} @app.post("/questions") def generate_questions(req: AnalyzeRequest): msg = client.messages.create( model="claude-sonnet-4-20250514", max_tokens=512, system="Generate 5 thoughtful questions about this text. Return JSON: {questions: []}", messages=[{"role": "user", "content": req.text}] ) return json.loads(msg.content[0].text)
Want live instruction and hands-on projects? Join the AI bootcamp — 3 days, 5 cities.
Before moving on, confirm understanding of these key concepts: