This feature is related to issue #372
It appears to me in the Swagger UI documentation on adding examples that the 'examples' key belongs to 'application/json'. It also appears to me that the key already exists in the MediaType model within fastapi.openapi.models but that only the 'schema' key is modified when writing the openapi spec through fastapi.openapi.utils.get_openapi_operation_request_body and then fastapi.openapi.utils.get_open_api_path and that the media type is nearly always passed around as a string rather than a dict or model object (please correct me if I'm wrong, I've only been using these particular tools for a few months.)
pydantic recently enabled schema_extra in samuelcolvin/pydantic#663 but I can't seem to get it to work with the swagger docs. At this time it's unclear to me if this is simply a part of the json schema spec that the swagger ui doesn't recognize yet, or if it's actually a deliberate deviation from the spec, or if I just can't figure it out. From the JSON Schema documentation on "examples" it states that this field "MUST" be an array. The aforementioned pydantic PR#663 and the associated example adhere to the spec well, but I cannot seem to build a request model using this newly minted ability that is supported by the swagger docs.
Here's a working reference swagger ui yaml file that builds the dropdown examples pick list in the swagger editor. I started with the fastapi.docs.body_fields.tutorial_002.py example and hand edited the swagger ui yaml to match the swagger examples docs for multiple examples:
openapi: 3.0.2
info:
title: Fast API
version: 0.1.0
paths:
'/items/{item_id}':
put:
summary: Update Item
operationId: update_item_items__item_id__put
parameters:
- required: true
schema:
title: Item Id
type: integer
name: item_id
in: path
requestBody:
content:
application/json:
schema:
title: Item
allOf:
- $ref: '#/components/schemas/Item'
examples:
test1:
summary: first test
value:
name: Foo
description: A very nice Item
price: 35.4
tax: 3.2
test2:
summary: second test
value:
name: Bar
description: Another very nice Item
price: 30
tax: 1.1
required: true
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
components:
schemas:
HTTPValidationError:
title: HTTPValidationError
type: object
properties:
detail:
title: Detail
type: array
items:
$ref: '#/components/schemas/ValidationError'
Item:
title: Item
required:
- name
- price
type: object
properties:
name:
title: Name
type: string
description:
title: Description
type: string
price:
title: Price
type: number
tax:
title: Tax
type: number
ValidationError:
title: ValidationError
required:
- loc
- msg
- type
type: object
properties:
loc:
title: Location
type: array
items:
type: string
msg:
title: Message
type: string
type:
title: Error Type
type: string
My hope is that either 1) There is another way to add multiple examples for a request body that I am missing or that 2) we can build a means for adding the "examples" dictionary to the media type so it appears in the swagger ui per their documented format, preferably building from the recent pydantic PR referenced above.
I recognize that a few things complicate this effort, including the fact that a fastapi Route can include multiple Body objects. This might mean that if we support the documented swagger format linked above for multiple examples, the attribute might have to be moved out of the Body function/class so that only one "examples" dict can be specified per route, or better yet, per content media type somehow.
With some direction I think I would be able to help implement this, since it's not a mission critical feature for the lead developers.
Bump. Is this not currently possible, or just low priority?
My use case is that I’m developing a containerized RPC style api for my client to deploy on a private internal server, and I want to embed a few examples for each endpoint to help them understand how the data they submit will be validated and returned, especially in case of api-internal errors (e.g they submit a valid float value to the service but when the api runs the numbers, that value resulted in an error). I’m hoping to embed both a ‘valid’ submission and an ‘invalid’ one for each api endpoint, but I can’t seem to make it work in even a simple test case.
Here's how you can add examples to your schema, and more details about what works in OpenAPI, what in JSON Schema, and what in Swagger UI: https://fastapi.tiangolo.com/tutorial/schema-extra-example/
In short, this doesn't really depend on FastAPI but on the standards and on Swagger UI.
Hi @tiangolo, thanks for this reply and thanks for the continued improvements to this library and to its docs.
It seems that the docs focus on defining one example per body parameter so that in case there are multiple bodies with examples, we can safely combine them to render the docs. This is great, and I have no trouble using the example functionality described in the docs which enable one example per route.
The functionality that I'm hoping to explore would allow me to define multiple complete but separate/mutually exclusive examples by embedding them into the media type. This is possible per the OpenAPI spec here and it appears that we can leverage the fastapidata model described by fastapi.openapi.models.MediaType
It appears that the infrastructure is already written within FastAPI to build objects that allow OpenAPI to render examples as pick lists that match the examples=Dict[str, Union[Example, Reference] pattern, such as MediaType, Parameter, Components and several others; though I think my use case could be addressed by getting it into just the media type.
Moving from the models to the utility functions that actually construct the OpenAPI json object, I notice that fastapi.openapi.utils.get_openapi_operation_request_body concludes with this line:
request_body_oai["content"] = {request_media_type: {"schema": body_schema}}
Which is great! Maybe. I haven't tested this yet to know if adding keys here actually solves my issue, though I will try tomorrow.
If we can find a way to make one of these utilities also add an examples key:value pair to the request_media_type dictionary shown above, then I think we would be able to support multiple examples for a single route in the interactive docs. The tricky bit is now determining how to pass this information to the OpenAPI constructor methods.
Thanks again for taking the time to think about this, I know it's a bit off the priority path.
Ok, I have a solution to this but it's a bit inelegant and naive... and it only works if the route has only one Body parameter (though based on how this keyword is parsed by OpenAPI, this should be an obvious limit the api designer would have to place upon themselves).
do note that the diff is quite minimal for the code golfers out there. I've identified the diff in the updated function below:
fastapi.openapi.utils.get_openapi_operation_request_body
def get_openapi_operation_request_body(
*, body_field: Optional[ModelField], model_name_map: Dict[Type[BaseModel], str]
) -> Optional[Dict]:
if not body_field:
return None
assert isinstance(body_field, ModelField)
body_schema, _, _ = field_schema(
body_field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
)
field_info = cast(Body, get_field_info(body_field))
request_media_type = field_info.media_type
required = body_field.required
request_body_oai: Dict[str, Any] = {}
if required:
request_body_oai["required"] = required
request_body_oai["content"] = {request_media_type: {"schema": body_schema}}
# begin diff
examples = body_schema.get("examples")
if examples:
request_body_oai["content"][request_media_type]["examples"] = examples
# end diff
return request_body_oai
This solution leverages the existing infrastructure for utilizing the **extra catchall from the Body object, which, with this alteration, knows what to do with the existence of 'examples' in the requestBody that this utility function builds.
_Limitations_
Body objects into a single composite object so that the route has only one Body. Note that they already have to do this for the 'embed' kwarg to be relevant.Body object fields mapped only to schema entries, and never to higher level entities in the json spec or object hierarchy. This was more elegant, but preserving it would likely mean a much _much_ larger diff for revealing access to the MediaType object during route building e.g., maybe adding a kwarg to all of the routing.Route calls? I don't actually know, I stopped pursuing this when I realized how burdensome any changes to the api of the routing.py functions will be and I didn't want this very minor feature to become a major pain to maintain.Anyway, I don't expect this 3 line patch to be the way you want to go, but if it is and you would like me to prepare a PR with a working example/docs_src tutorial/docs addendum I'll draft it gladly. The existence of this project(fastapi) and the prototype projects for building things with containers have very valuable for me and I'd be happy to contribute.
went ahead and opened a PR so the diff and example/tutorial is easier to review.
In fact, openapi 3.0.3 seems to allow the examples keyword in parameters, request bodies and responses. See section Example Object Examples
The externalValue seems to be interesting for reusing the json responses in testing / mocks.
Most helpful comment
went ahead and opened a PR so the diff and example/tutorial is easier to review.