-
-
Save linknum23/24ae644c61764befe6b309da0a6be129 to your computer and use it in GitHub Desktop.
Adding multiple request and response examples to swagger docs in fastAPI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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