Last active
October 8, 2024 04:37
-
-
Save vigneshjs/f17b3a2ec9ab9a606f37572bfdd1d76c to your computer and use it in GitHub Desktop.
Adding multiple request body 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, | |
) | |
# Adding examples present in pydancticModel.schema_extra into openAPI schema | |
for route in app.routes: | |
if isinstance(route, routing.APIRoute): | |
# bodyField refers to the field present in the function that is called when route matches | |
bodyField = route.body_field | |
if bodyField: | |
# Use pydantic schema_json() to get json schema representation (string) of the pydantic model | |
modelSchema = bodyField.type_.schema_json() | |
if modelSchema: | |
# Parse dict object from json string | |
jsonModelSchema = json.loads(modelSchema) | |
if "examples" in jsonModelSchema: | |
examples = jsonModelSchema['examples'] | |
for method in route.methods: | |
# We can have requestBody examples only for POST and PUT methods | |
if method == "POST": | |
openapi_schema['paths'][route.path]["post"]['requestBody'][ | |
'content']['application/json']['examples'] = examples | |
elif method == "PUT": | |
openapi_schema['paths'][route.path]["put"]['requestBody'][ | |
'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