FastAPI for AI Applications Handbook · PRACTICAL GUIDE

Build REST APIs with Validation and Error Handling

Create reliable GET and POST API contracts with Pydantic validation, response models, meaningful HTTP status codes and useful client errors.

HANDBOOK JOURNEYByte 2 of 5View all Bytes
HANDBOOK JOURNEYByte 2 of 5

FastAPI for AI Applications Handbook

23 min focused reading
  1. BYTE 01What Is FastAPI?
  2. 03BYTE 03Connect FastAPI with Databases and External Services
  3. 04BYTE 04Build and Stream a Generative AI API
  4. 05BYTE 05Secure, Test and Deploy a Production FastAPI Application
FAMILIAR SCENARIO

A railway form is checked before booking

The counter checks journey date, passenger details and required fields before attempting a reservation, then explains what must be corrected.

01Input
02Validate
03Process
04Clear result

Connect the idea: Validation rejects unusable requests before business logic runs.

FASTAPI HANDBOOK 02

Practical outcome

You will define a trustworthy /questions contract that rejects unsafe input, returns predictable output and explains recoverable errors to clients.

SAFE REST CONTRACTReject bad input before business logic runs
FOLLOW THE FLOW
01
Request bodyUntrusted JSON
02
Pydantic modelValidate + parse
03
Service logicPerform work
04
Typed responsePredictable output
Remember: Validation protects the application boundary; meaningful errors help clients recover.
VALIDATION LAB

Send three payloads through the same API contract

INTERACTIVE
REQUEST CASEValid request Case 1 of 3
1question is a string2length is within limit3200 · accepted

Why it mattersValid data reaches business logic.

Every request is untrusted

The client may send missing fields, the wrong type, an empty question or a document scope it should not control. Validation converts unknown network data into a known application object—or stops the request before business logic runs.

Define the request model

PYTHON
01from pydantic import BaseModel, Field0203class QuestionRequest(BaseModel):04    question: str = Field(min_length=3, max_length=2000)05    conversation_id: str | None = None06    stream: bool = False

FastAPI reads JSON into this model. If validation succeeds, the route receives a QuestionRequest. If it fails, FastAPI returns a structured validation error.

PYTHON
01from fastapi import FastAPI, status0203app = FastAPI()0405@app.post("/questions", status_code=status.HTTP_202_ACCEPTED)06def submit_question(payload: QuestionRequest):07    return {08        "request_id": "req_123",09        "status": "accepted",10        "question": payload.question,11    }

Validate meaning, not only data type

A string containing spaces technically has the right type but no useful question.

PYTHON
01from pydantic import BaseModel, Field, field_validator0203class QuestionRequest(BaseModel):04    question: str = Field(min_length=3, max_length=2000)05    conversation_id: str | None = None0607    @field_validator("question")08    @classmethod09    def question_must_have_content(cls, value: str) -> str:10        cleaned = value.strip()11        if not cleaned:12            raise ValueError("question must contain visible text")13        return cleaned

Validation should establish format and safe boundaries. Authorisation and domain decisions still belong in application services.

Control the response contract

PYTHON
01class Citation(BaseModel):02    source_id: str03    title: str04    page: int | None = None0506class AnswerResponse(BaseModel):07    request_id: str08    answer: str09    citations: list[Citation]10    insufficient_evidence: bool1112@app.post("/answers", response_model=AnswerResponse)13def answer_question(payload: QuestionRequest):14    return build_answer(payload)

A response model documents the output and prevents accidental fields from escaping. For example, a database object may include internal notes or provider payloads that clients should never receive.

Use status codes to communicate outcomes

StatusMeaning in this project
200 OKAnswer returned successfully
201 CreatedNew conversation or document created
202 AcceptedLong-running ingestion accepted
400 Bad RequestRequest is syntactically valid but violates a business rule
401 UnauthorizedAuthentication is missing or invalid
403 ForbiddenIdentity is known but lacks permission
404 Not FoundRequested resource does not exist in the caller’s scope
422 Unprocessable ContentRequest validation failed
429 Too Many RequestsRate or cost limit exceeded
503 Service UnavailableRequired provider is temporarily unavailable

Return useful application errors

PYTHON
01from fastapi import HTTPException, status0203@app.get("/conversations/{conversation_id}")04def get_conversation(conversation_id: str):05    conversation = repository.find(conversation_id)06    if conversation is None:07        raise HTTPException(08            status_code=status.HTTP_404_NOT_FOUND,09            detail={10                "code": "conversation_not_found",11                "message": "The conversation could not be found.",12            },13        )14    return conversation

Give clients a stable error code for program logic and a safe message for people. Do not expose stack traces, SQL statements, model prompts or provider secrets.

Create a consistent error envelope

JSON
01{02  "error": {03    "code": "insufficient_evidence",04    "message": "No authorised source can answer this question.",05    "request_id": "req_123",06    "retryable": false07  }08}

The request ID connects the client’s error with server logs. retryable helps a client decide whether another attempt makes sense.

Real-time scenario: invalid AI question

SEE IT IN PRACTICE

Reject early, explain clearly

A mobile client sends a 12,000-character prompt and a field named access_group: finance. The Pydantic model rejects the oversized prompt. The server ignores caller-provided access claims and derives scope from authenticated identity. The API returns a clear validation error without calling retrieval or the LLM—saving cost and reducing risk.

Common mistakes

AVOID THESE

Common mistakes

  • Accepting unrestricted dictionaries instead of explicit request models.
  • Returning raw database or provider objects to the client.
  • Catching every exception and converting it to 200 OK.
  • Sending internal exception messages and stack traces over the API.
  • Treating client-provided roles or tenant IDs as authorised identity.

Interview bit

CAREER

Pydantic validation versus business validation

Pydantic validates and parses the shape of incoming data: types, lengths and field rules. Business validation checks domain state, such as whether a conversation exists or a document is active. Authorisation checks whether this identity may perform the operation. I keep those concerns separate so errors and tests remain precise.

Key takeaways

REMEMBER THIS

Key takeaways

  • Validate untrusted network input before expensive AI work begins.
  • Request models define accepted input; response models define exposed output.
  • Use status codes and stable error codes to help clients recover.
  • Never leak internal exceptions or secret provider payloads.
  • Authentication claims must come from a verified identity, not the request body.

Frequently asked questions

Why validate before calling an AI model? Early validation rejects unusable input before it consumes model capacity, external API calls or database work.

What is the difference between a request model and a response model? A request model validates incoming data. A response model controls and documents the shape returned to the client.

Should every application error return status 500? No. Use a status that represents validation, authentication, permission, a missing resource or an unexpected server failure.

Interactive Knowledge Check

LESSON CHECKPOINTConfirm the concept before moving forward

Choose an answer, inspect the explanation and explain the idea in your own words.

RETENTION
Learning rule: explain the answer in your own words before checking the next Byte.

Primary sources

OPTIONAL LEARNING CONNECTIONS

Continue by concept

Choose only what supports your next goal. This Byte does not require either link.