8.1 KiB
FastAPI – Response Model and JSONResponse
Overview
This document explains two important FastAPI response concepts:
- Using
response_modelto control what data is returned to the client - Using
JSONResponsewhen you need explicit control over the response body, status code, or headers
Response models are especially useful when you want to hide sensitive fields such as passwords from API responses.
1. Response Model
Incorrect Example
The following code has several issues:
from fastapi import FastAPI, status , HTTPExption
from pydantic import BaseModel
app = FastAPI()
class usersin(BaseModel):
username: str
pass: str
class usersout(BaseModel):
username: str
@app.post("/user")
def home(user: usersin, responce_model=usersout):
return user
Problems in the Code
1. HTTPExption is misspelled
Correct import:
HTTPException
2. pass cannot be used as a field name
pass is a reserved keyword in Python.
Instead of:
pass: str
Use:
password: str
3. response_model is written in the wrong place
This is incorrect:
def home(user: usersin, responce_model=usersout):
response_model must be passed inside the route decorator.
Correct:
@app.post("/user", response_model=UserOut)
4. responce_model is misspelled
Correct spelling:
response_model
2. Correct Response Model Example
Create or update main.py with the following content:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
class UserOut(BaseModel):
username: str
@app.post("/user", response_model=UserOut)
def create_user(user: UserIn):
return user
3. How Response Model Works
Input Model
class UserIn(BaseModel):
username: str
password: str
This model defines the data that the API receives from the client.
Example request body:
{
"username": "abbas",
"password": "123456"
}
The API accepts both fields:
username
password
Output Model
class UserOut(BaseModel):
username: str
This model defines the data that the API returns to the client.
Even though the endpoint receives the password, the response only returns the username.
Example response:
{
"username": "abbas"
}
The password is removed from the response automatically.
4. Endpoint Definition
@app.post("/user", response_model=UserOut)
def create_user(user: UserIn):
return user
This creates a POST endpoint at:
POST /user
The endpoint receives data based on UserIn and returns data based on UserOut.
FastAPI uses response_model to filter the response before sending it to the client.
5. Example Request
Using curl
curl -X POST "http://localhost:8000/user" \
-H "Content-Type: application/json" \
-d '{"username": "abbas", "password": "123456"}'
Response
{
"username": "abbas"
}
The password is not included in the response.
6. Why Use Response Models
Response models are useful because they help you:
Protect sensitive data Keep API responses consistent Control exactly what the client receives Improve automatic documentation Validate response data before sending it Separate input schemas from output schemas
7. Better Version with Status Code
For user creation endpoints, it is better to return 201 Created.
from fastapi import FastAPI, status
from pydantic import BaseModel
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
class UserOut(BaseModel):
username: str
@app.post(
"/user",
response_model=UserOut,
status_code=status.HTTP_201_CREATED
)
def create_user(user: UserIn):
return user
8. JSONResponse
FastAPI automatically converts Python dictionaries into JSON responses.
For most endpoints, this is enough:
@app.get("/")
def home():
return {"msg": "API is working"}
However, FastAPI also allows you to use JSONResponse when you need more control.
9. Example Application Using JSONResponse
Create or update main.py with the following content:
from fastapi import FastAPI, status
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get("/")
def home():
return JSONResponse(
content={"msg": "API is working"},
status_code=status.HTTP_200_OK
)
10. Response Behavior
Endpoint
GET /
Response Body
{
"msg": "API is working"
}
HTTP Status Code
200 OK
11. Default Response vs JSONResponse
Default FastAPI Response
@app.get("/")
def home():
return {"msg": "API is working"}
This is the recommended style for most simple APIs.
FastAPI automatically serializes the dictionary into JSON.
Explicit JSONResponse
return JSONResponse(
content={"msg": "API is working"},
status_code=status.HTTP_200_OK
)
This gives more direct control over the response.
12. When to Use JSONResponse
Use JSONResponse when you need to:
Return dynamic status codes Add custom headers Customize the response structure manually Return responses from exception handlers Return responses from middleware Override FastAPI’s default response behavior
13. Example: JSONResponse with Custom Status Code
from fastapi import FastAPI, status
from fastapi.responses import JSONResponse
app = FastAPI()
@app.post("/login")
def login():
return JSONResponse(
content={"msg": "Login successful"},
status_code=status.HTTP_200_OK
)
14. Example: JSONResponse with Headers
from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get("/custom")
def custom_response():
return JSONResponse(
content={"msg": "Custom response"},
headers={"X-App-Version": "1.0.0"}
)
15. Complete Example with Response Model and JSONResponse
from fastapi import FastAPI, status
from fastapi.responses import JSONResponse
from pydantic import BaseModel
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
class UserOut(BaseModel):
username: str
@app.get("/")
def home():
return JSONResponse(
content={"msg": "API is working"},
status_code=status.HTTP_200_OK
)
@app.post(
"/user",
response_model=UserOut,
status_code=status.HTTP_201_CREATED
)
def create_user(user: UserIn):
return user
16. Running the Application
Start the FastAPI application using uvicorn:
uvicorn main:app --reload
The API will run at:
http://localhost:8000
Interactive API documentation will be available at:
http://localhost:8000/docs
17. Best Practices
Use response_model to control API output.
Never return sensitive data such as passwords, tokens, or secrets.
Use separate models for input and output.
Use clear class names such as UserIn and UserOut.
Use password instead of pass because pass is a reserved Python keyword.
Place response_model inside the route decorator, not inside the function parameters.
Prefer returning normal dictionaries for simple responses.
Use JSONResponse only when extra control is required.
Use proper HTTP status codes, such as:
200 OK
201 Created
400 Bad Request
401 Unauthorized
404 Not Found
500 Internal Server Error
Do not use uvicorn --reload in production.
18. DevOps Production Note
In production, the FastAPI application should usually run behind a production-grade ASGI server setup and a reverse proxy.
A common production stack is:
FastAPI
Gunicorn with Uvicorn workers
Nginx or Traefik
Docker or Kubernetes
PostgreSQL or another persistent database
The development command:
uvicorn main:app --reload
is only for local development.
For production, use a more stable process configuration, such as Gunicorn with Uvicorn workers, container health checks, logging, monitoring, and proper secret management.