Skip to content

Instantly share code, notes, and snippets.

@linknum23
Forked from vigneshjs/app.py
Last active May 21, 2021 19:28
Show Gist options
  • Save linknum23/24ae644c61764befe6b309da0a6be129 to your computer and use it in GitHub Desktop.
Save linknum23/24ae644c61764befe6b309da0a6be129 to your computer and use it in GitHub Desktop.
Adding multiple request and response examples to swagger docs in fastAPI
"""
FastAPI uses pydantic models to validate the API request body and also generate the swagger documentation. Since the schema
generated by pydantic only comply to JSON schema specification and not to openAPI specification, swagger documentation
generated from pydantic models do not support adding multiple examples for a request body.
Ref: https://fastapi.tiangolo.com/tutorial/schema-extra-example/#technical-details
In the following code, I have extended fastAPI openAPI schema to include multiple request body examples.
"""
import json
from fastapi import FastAPI, routing, status
from fastapi.openapi.utils import get_openapi
from fastapi.responses import Response
from pydantic import BaseModel
app = FastAPI()
# Defining a basic pydantic class that will be used by fastAPI to validate request body and generate swagger
class Sample(BaseModel):
"""
This is a example pydantic model
"""
name: str
email: str
mobile_number: str
password: str
otp: str
class Config:
# Follow openAPI 3.0 specification for defining examples. Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#example-object
schema_extra = {
"examples": {
"Login with otp": {
"description": "Allows to user to login with mobile_number and OTP",
"value": {
"mobile_number": "+9157878787878",
"opt": "123321"
}
},
"Login with email": {
"description": "Allows to user to login with email and password",
"value": {
"email": "[email protected]",
"password": "userPassword"
}
}
}
}
@app.post("/login", status_code=200)
async def login(body: Sample):
"""
Login user
"""
return Response({
"status": "success"
}, status_code=status.HTTP_200_OK)
# Extending openapi
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Sample API",
version="0.1.0",
description="These APIs will be used to manage developer portal and configure applications and permissions",
routes=app.routes,
)
for route in app.routes:
if isinstance(route, APIRoute):
try:
if route.body_field:
req_model_json = route.body_field.type_.schema_json()
else:
req_model_json = ''
except:
req_model_json = ''
try:
if route.response_field:
resp_model_json = route.response_field.type_.schema_json()
else:
resp_model_json = ''
except:
resp_model_json = ''
if req_model_json:
req_model = json.loads(req_model_json)
if "examples" in req_model:
examples = req_model['examples']
for method in route.methods:
# Only for POST, PATCH, and PUT methods have a request body
if method in {"POST", "PATCH", "PUT"}:
openapi_schema['paths'][route.path][method.lower()]['requestBody'][
'content']['application/json']['examples'] = examples
if resp_model_json:
resp_model = json.loads(resp_model_json)
if 'examples' in resp_model:
examples = resp_model['examples']
for method in route.methods:
openapi_schema['paths'][route.path][method.lower()]['responses']['200'][
'content']['application/json']['examples'] = examples
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment