From e10a4375f983b7b87ec6873b3c0b48cb482efbab Mon Sep 17 00:00:00 2001 From: Austin Orr Date: Wed, 5 May 2021 11:20:56 -0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20adding=20mult?= =?UTF-8?q?iple=20examples=20in=20request=20bodies=20and=20path,=20query,?= =?UTF-8?q?=20cookie,=20and=20header=20params=20(#1267)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../docs/img/tutorial/body-fields/image02.png | Bin 0 -> 93828 bytes docs/en/docs/tutorial/schema-extra-example.md | 89 +- docs_src/schema_extra_example/tutorial004.py | 52 + fastapi/openapi/utils.py | 13 +- fastapi/param_functions.py | 31 +- fastapi/params.py | 36 +- tests/test_schema_extra_examples.py | 889 ++++++++++++++++++ .../test_schema_extra_example/__init__.py | 0 .../test_tutorial004.py | 134 +++ 9 files changed, 1220 insertions(+), 24 deletions(-) create mode 100644 docs/en/docs/img/tutorial/body-fields/image02.png create mode 100644 docs_src/schema_extra_example/tutorial004.py create mode 100644 tests/test_schema_extra_examples.py create mode 100644 tests/test_tutorial/test_schema_extra_example/__init__.py create mode 100644 tests/test_tutorial/test_schema_extra_example/test_tutorial004.py diff --git a/docs/en/docs/img/tutorial/body-fields/image02.png b/docs/en/docs/img/tutorial/body-fields/image02.png new file mode 100644 index 0000000000000000000000000000000000000000..f307bb8ecd30de3049e33025182616f1b9964be4 GIT binary patch literal 93828 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's docs: Schema customization: +You can declare an `example` for a Pydantic model using `Config` and `schema_extra`, as described in Pydantic's docs: Schema customization: ```Python hl_lines="15-23" {!../../../docs_src/schema_extra_example/tutorial001.py!} ``` -That extra info will be added as-is to the output JSON Schema. +That extra info will be added as-is to the output **JSON Schema** for that model, and it will be used in the API docs. + +!!! tip + You could use the same technique to extend the JSON Schema and add your own custom extra info. + + For example you could use it to add metadata for a frontend user interface, etc. ## `Field` additional arguments -In `Field`, `Path`, `Query`, `Body` and others you'll see later, you can also declare extra info for the JSON Schema by passing any other arbitrary arguments to the function, for example, to add an `example`: +When using `Field()` with Pydantic models, you can also declare extra info for the **JSON Schema** by passing any other arbitrary arguments to the function. + +You can use this to add `example` for each field: ```Python hl_lines="4 10-13" {!../../../docs_src/schema_extra_example/tutorial002.py!} ``` !!! warning - Keep in mind that those extra arguments passed won't add any validation, only annotation, for documentation purposes. + Keep in mind that those extra arguments passed won't add any validation, only extra information, for documentation purposes. + +## `example` and `examples` in OpenAPI + +When using any of: -## `Body` additional arguments +* `Path()` +* `Query()` +* `Header()` +* `Cookie()` +* `Body()` +* `Form()` +* `File()` -The same way you can pass extra info to `Field`, you can do the same with `Path`, `Query`, `Body`, etc. +you can also declare a data `example` or a group of `examples` with additional information that will be added to **OpenAPI**. -For example, you can pass an `example` for a body request to `Body`: +### `Body` with `example` + +Here we pass an `example` of the data expected in `Body()`: ```Python hl_lines="21-26" {!../../../docs_src/schema_extra_example/tutorial003.py!} ``` -## Example in the docs UI +### Example in the docs UI With any of the methods above it would look like this in the `/docs`: +### `Body` with multiple `examples` + +Alternatively to the single `example`, you can pass `examples` using a `dict` with **multiple examples**, each with extra information that will be added to **OpenAPI** too. + +The keys of the `dict` identify each example, and each value is another `dict`. + +Each specific example `dict` in the `examples` can contain: + +* `summary`: Short description for the example. +* `description`: A long description that can contain Markdown text. +* `value`: This is the actual example shown, e.g. a `dict`. +* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`. + +```Python hl_lines="22-48" +{!../../../docs_src/schema_extra_example/tutorial004.py!} +``` + +### Examples in the docs UI + +With `examples` added to `Body()` the `/docs` would look like: + + + ## Technical Details -About `example` vs `examples`... +!!! warning + These are very technical details about the standards **JSON Schema** and **OpenAPI**. + + If the ideas above already work for you, that might me enough, and you probably don't need these details, feel free to skip them. + +When you add an example inside of a Pydantic model, using `schema_extra` or `Field(example="something")` that example is added to the **JSON Schema** for that Pydantic model. + +And that **JSON Schema** of the Pydantic model is included in the **OpenAPI** of your API, and then it's used in the docs UI. + +**JSON Schema** doesn't really have a field `example` in the standards. Recent versions of JSON Schema define a field `examples`, but OpenAPI 3.0.3 is based on an older version of JSON Schema that didn't have `examples`. + +So, OpenAPI 3.0.3 defined its own `example` for the modified version of **JSON Schema** it uses, for the same purpose (but it's a single `example`, not `examples`), and that's what is used by the API docs UI (using Swagger UI). -JSON Schema defines a field `examples` in the most recent versions, but OpenAPI is based on an older version of JSON Schema that didn't have `examples`. +So, although `example` is not part of JSON Schema, it is part of OpenAPI's custom version of JSON Schema, and that's what will be used by the docs UI. -So, OpenAPI defined its own `example` for the same purpose (as `example`, not `examples`), and that's what is used by the docs UI (using Swagger UI). +But when you use `example` or `examples` with any of the other utilities (`Query()`, `Body()`, etc.) those examples are not added to the JSON Schema that describes that data (not even to OpenAPI's own version of JSON Schema), they are added directly to the *path operation* declaration in OpenAPI (outside the parts of OpenAPI that use JSON Schema). -So, although `example` is not part of JSON Schema, it is part of OpenAPI, and that's what will be used by the docs UI. +For `Path()`, `Query()`, `Header()`, and `Cookie()`, the `example` or `examples` are added to the OpenAPI definition, to the `Parameter Object` (in the specification). -## Other info +And for `Body()`, `File()`, and `Form()`, the `example` or `examples` are equivalently added to the OpenAPI definition, to the `Request Body Object`, in the field `content`, on the `Media Type Object` (in the specification). -The same way, you could add your own custom extra info that would be added to the JSON Schema for each model, for example to customize a frontend user interface, etc. +On the other hand, there's a newer version of OpenAPI: **3.1.0**, recently released. It is based on the latest JSON Schema and most of the modifications from OpenAPI's custom version of JSON Schema are removed, in exchange of the features from the recent versions of JSON Schema, so all these small differences are reduced. Nevertheless, Swagger UI currently doesn't support OpenAPI 3.1.0, so, for now, it's better to continue using the ideas above. diff --git a/docs_src/schema_extra_example/tutorial004.py b/docs_src/schema_extra_example/tutorial004.py new file mode 100644 index 000000000..9f0e8b437 --- /dev/null +++ b/docs_src/schema_extra_example/tutorial004.py @@ -0,0 +1,52 @@ +from typing import Optional + +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Item = Body( + ..., + examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), +): + results = {"item_id": item_id, "item": item} + return results diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 410ba9389..6f749ef9c 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -21,7 +21,7 @@ from fastapi.utils import ( get_model_definitions, ) from pydantic import BaseModel -from pydantic.fields import ModelField +from pydantic.fields import ModelField, Undefined from pydantic.schema import ( field_schema, get_flat_models_from_fields, @@ -101,6 +101,10 @@ def get_openapi_operation_parameters( } if field_info.description: parameter["description"] = field_info.description + if field_info.examples: + parameter["examples"] = jsonable_encoder(field_info.examples) + elif field_info.example != Undefined: + parameter["example"] = jsonable_encoder(field_info.example) if field_info.deprecated: parameter["deprecated"] = field_info.deprecated parameters.append(parameter) @@ -124,7 +128,12 @@ def get_openapi_operation_request_body( request_body_oai: Dict[str, Any] = {} if required: request_body_oai["required"] = required - request_body_oai["content"] = {request_media_type: {"schema": body_schema}} + request_media_content: Dict[str, Any] = {"schema": body_schema} + if field_info.examples: + request_media_content["examples"] = jsonable_encoder(field_info.examples) + elif field_info.example != Undefined: + request_media_content["example"] = jsonable_encoder(field_info.example) + request_body_oai["content"] = {request_media_type: request_media_content} return request_body_oai diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py index 9ebb59100..ff65d7271 100644 --- a/fastapi/param_functions.py +++ b/fastapi/param_functions.py @@ -1,6 +1,7 @@ -from typing import Any, Callable, Optional, Sequence +from typing import Any, Callable, Dict, Optional, Sequence from fastapi import params +from pydantic.fields import Undefined def Path( # noqa: N802 @@ -16,6 +17,8 @@ def Path( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any, ) -> Any: @@ -31,6 +34,8 @@ def Path( # noqa: N802 min_length=min_length, max_length=max_length, regex=regex, + example=example, + examples=examples, deprecated=deprecated, **extra, ) @@ -49,6 +54,8 @@ def Query( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any, ) -> Any: @@ -64,6 +71,8 @@ def Query( # noqa: N802 min_length=min_length, max_length=max_length, regex=regex, + example=example, + examples=examples, deprecated=deprecated, **extra, ) @@ -83,6 +92,8 @@ def Header( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any, ) -> Any: @@ -99,6 +110,8 @@ def Header( # noqa: N802 min_length=min_length, max_length=max_length, regex=regex, + example=example, + examples=examples, deprecated=deprecated, **extra, ) @@ -117,6 +130,8 @@ def Cookie( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any, ) -> Any: @@ -132,6 +147,8 @@ def Cookie( # noqa: N802 min_length=min_length, max_length=max_length, regex=regex, + example=example, + examples=examples, deprecated=deprecated, **extra, ) @@ -152,6 +169,8 @@ def Body( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, **extra: Any, ) -> Any: return params.Body( @@ -168,6 +187,8 @@ def Body( # noqa: N802 min_length=min_length, max_length=max_length, regex=regex, + example=example, + examples=examples, **extra, ) @@ -186,6 +207,8 @@ def Form( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, **extra: Any, ) -> Any: return params.Form( @@ -201,6 +224,8 @@ def Form( # noqa: N802 min_length=min_length, max_length=max_length, regex=regex, + example=example, + examples=examples, **extra, ) @@ -219,6 +244,8 @@ def File( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, **extra: Any, ) -> Any: return params.File( @@ -234,6 +261,8 @@ def File( # noqa: N802 min_length=min_length, max_length=max_length, regex=regex, + example=example, + examples=examples, **extra, ) diff --git a/fastapi/params.py b/fastapi/params.py index aa3269a80..3cab98b78 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -1,7 +1,7 @@ from enum import Enum -from typing import Any, Callable, Optional, Sequence +from typing import Any, Callable, Dict, Optional, Sequence -from pydantic.fields import FieldInfo +from pydantic.fields import FieldInfo, Undefined class ParamTypes(Enum): @@ -28,10 +28,14 @@ class Param(FieldInfo): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any, ): self.deprecated = deprecated + self.example = example + self.examples = examples super().__init__( default, alias=alias, @@ -68,6 +72,8 @@ class Path(Param): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any, ): @@ -85,6 +91,8 @@ class Path(Param): max_length=max_length, regex=regex, deprecated=deprecated, + example=example, + examples=examples, **extra, ) @@ -106,6 +114,8 @@ class Query(Param): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any, ): @@ -122,6 +132,8 @@ class Query(Param): max_length=max_length, regex=regex, deprecated=deprecated, + example=example, + examples=examples, **extra, ) @@ -144,6 +156,8 @@ class Header(Param): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any, ): @@ -161,6 +175,8 @@ class Header(Param): max_length=max_length, regex=regex, deprecated=deprecated, + example=example, + examples=examples, **extra, ) @@ -182,6 +198,8 @@ class Cookie(Param): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any, ): @@ -198,6 +216,8 @@ class Cookie(Param): max_length=max_length, regex=regex, deprecated=deprecated, + example=example, + examples=examples, **extra, ) @@ -219,10 +239,14 @@ class Body(FieldInfo): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, **extra: Any, ): self.embed = embed self.media_type = media_type + self.example = example + self.examples = examples super().__init__( default, alias=alias, @@ -258,6 +282,8 @@ class Form(Body): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, **extra: Any, ): super().__init__( @@ -274,6 +300,8 @@ class Form(Body): min_length=min_length, max_length=max_length, regex=regex, + example=example, + examples=examples, **extra, ) @@ -294,6 +322,8 @@ class File(Form): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, + example: Any = Undefined, + examples: Optional[Dict[str, Any]] = None, **extra: Any, ): super().__init__( @@ -309,6 +339,8 @@ class File(Form): min_length=min_length, max_length=max_length, regex=regex, + example=example, + examples=examples, **extra, ) diff --git a/tests/test_schema_extra_examples.py b/tests/test_schema_extra_examples.py new file mode 100644 index 000000000..3e0d846cd --- /dev/null +++ b/tests/test_schema_extra_examples.py @@ -0,0 +1,889 @@ +from fastapi import Body, Cookie, FastAPI, Header, Path, Query +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + data: str + + class Config: + schema_extra = {"example": {"data": "Data in schema_extra"}} + + +@app.post("/schema_extra/") +def schema_extra(item: Item): + return item + + +@app.post("/example/") +def example(item: Item = Body(..., example={"data": "Data in Body example"})): + return item + + +@app.post("/examples/") +def examples( + item: Item = Body( + ..., + examples={ + "example1": { + "summary": "example1 summary", + "value": {"data": "Data in Body examples, example1"}, + }, + "example2": {"value": {"data": "Data in Body examples, example2"}}, + }, + ) +): + return item + + +@app.post("/example_examples/") +def example_examples( + item: Item = Body( + ..., + example={"data": "Overriden example"}, + examples={ + "example1": {"value": {"data": "examples example_examples 1"}}, + "example2": {"value": {"data": "examples example_examples 2"}}, + }, + ) +): + return item + + +# TODO: enable these tests once/if Form(embed=False) is supported +# TODO: In that case, define if File() should support example/examples too +# @app.post("/form_example") +# def form_example(firstname: str = Form(..., example="John")): +# return firstname + + +# @app.post("/form_examples") +# def form_examples( +# lastname: str = Form( +# ..., +# examples={ +# "example1": {"summary": "last name summary", "value": "Doe"}, +# "example2": {"value": "Doesn't"}, +# }, +# ), +# ): +# return lastname + + +# @app.post("/form_example_examples") +# def form_example_examples( +# lastname: str = Form( +# ..., +# example="Doe overriden", +# examples={ +# "example1": {"summary": "last name summary", "value": "Doe"}, +# "example2": {"value": "Doesn't"}, +# }, +# ), +# ): +# return lastname + + +@app.get("/path_example/{item_id}") +def path_example( + item_id: str = Path( + ..., + example="item_1", + ), +): + return item_id + + +@app.get("/path_examples/{item_id}") +def path_examples( + item_id: str = Path( + ..., + examples={ + "example1": {"summary": "item ID summary", "value": "item_1"}, + "example2": {"value": "item_2"}, + }, + ), +): + return item_id + + +@app.get("/path_example_examples/{item_id}") +def path_example_examples( + item_id: str = Path( + ..., + example="item_overriden", + examples={ + "example1": {"summary": "item ID summary", "value": "item_1"}, + "example2": {"value": "item_2"}, + }, + ), +): + return item_id + + +@app.get("/query_example/") +def query_example( + data: str = Query( + None, + example="query1", + ), +): + return data + + +@app.get("/query_examples/") +def query_examples( + data: str = Query( + None, + examples={ + "example1": {"summary": "Query example 1", "value": "query1"}, + "example2": {"value": "query2"}, + }, + ), +): + return data + + +@app.get("/query_example_examples/") +def query_example_examples( + data: str = Query( + None, + example="query_overriden", + examples={ + "example1": {"summary": "Qeury example 1", "value": "query1"}, + "example2": {"value": "query2"}, + }, + ), +): + return data + + +@app.get("/header_example/") +def header_example( + data: str = Header( + None, + example="header1", + ), +): + return data + + +@app.get("/header_examples/") +def header_examples( + data: str = Header( + None, + examples={ + "example1": {"summary": "header example 1", "value": "header1"}, + "example2": {"value": "header2"}, + }, + ), +): + return data + + +@app.get("/header_example_examples/") +def header_example_examples( + data: str = Header( + None, + example="header_overriden", + examples={ + "example1": {"summary": "Qeury example 1", "value": "header1"}, + "example2": {"value": "header2"}, + }, + ), +): + return data + + +@app.get("/cookie_example/") +def cookie_example( + data: str = Cookie( + None, + example="cookie1", + ), +): + return data + + +@app.get("/cookie_examples/") +def cookie_examples( + data: str = Cookie( + None, + examples={ + "example1": {"summary": "cookie example 1", "value": "cookie1"}, + "example2": {"value": "cookie2"}, + }, + ), +): + return data + + +@app.get("/cookie_example_examples/") +def cookie_example_examples( + data: str = Cookie( + None, + example="cookie_overriden", + examples={ + "example1": {"summary": "Qeury example 1", "value": "cookie1"}, + "example2": {"value": "cookie2"}, + }, + ), +): + return data + + +client = TestClient(app) + + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/schema_extra/": { + "post": { + "summary": "Schema Extra", + "operationId": "schema_extra_schema_extra__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/example/": { + "post": { + "summary": "Example", + "operationId": "example_example__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"}, + "example": {"data": "Data in Body example"}, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/examples/": { + "post": { + "summary": "Examples", + "operationId": "examples_examples__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"}, + "examples": { + "example1": { + "summary": "example1 summary", + "value": { + "data": "Data in Body examples, example1" + }, + }, + "example2": { + "value": {"data": "Data in Body examples, example2"} + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/example_examples/": { + "post": { + "summary": "Example Examples", + "operationId": "example_examples_example_examples__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"}, + "examples": { + "example1": { + "value": {"data": "examples example_examples 1"} + }, + "example2": { + "value": {"data": "examples example_examples 2"} + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/path_example/{item_id}": { + "get": { + "summary": "Path Example", + "operationId": "path_example_path_example__item_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "string"}, + "example": "item_1", + "name": "item_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/path_examples/{item_id}": { + "get": { + "summary": "Path Examples", + "operationId": "path_examples_path_examples__item_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "string"}, + "examples": { + "example1": { + "summary": "item ID summary", + "value": "item_1", + }, + "example2": {"value": "item_2"}, + }, + "name": "item_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/path_example_examples/{item_id}": { + "get": { + "summary": "Path Example Examples", + "operationId": "path_example_examples_path_example_examples__item_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "string"}, + "examples": { + "example1": { + "summary": "item ID summary", + "value": "item_1", + }, + "example2": {"value": "item_2"}, + }, + "name": "item_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/query_example/": { + "get": { + "summary": "Query Example", + "operationId": "query_example_query_example__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Data", "type": "string"}, + "example": "query1", + "name": "data", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/query_examples/": { + "get": { + "summary": "Query Examples", + "operationId": "query_examples_query_examples__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Data", "type": "string"}, + "examples": { + "example1": { + "summary": "Query example 1", + "value": "query1", + }, + "example2": {"value": "query2"}, + }, + "name": "data", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/query_example_examples/": { + "get": { + "summary": "Query Example Examples", + "operationId": "query_example_examples_query_example_examples__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Data", "type": "string"}, + "examples": { + "example1": { + "summary": "Qeury example 1", + "value": "query1", + }, + "example2": {"value": "query2"}, + }, + "name": "data", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/header_example/": { + "get": { + "summary": "Header Example", + "operationId": "header_example_header_example__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Data", "type": "string"}, + "example": "header1", + "name": "data", + "in": "header", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/header_examples/": { + "get": { + "summary": "Header Examples", + "operationId": "header_examples_header_examples__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Data", "type": "string"}, + "examples": { + "example1": { + "summary": "header example 1", + "value": "header1", + }, + "example2": {"value": "header2"}, + }, + "name": "data", + "in": "header", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/header_example_examples/": { + "get": { + "summary": "Header Example Examples", + "operationId": "header_example_examples_header_example_examples__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Data", "type": "string"}, + "examples": { + "example1": { + "summary": "Qeury example 1", + "value": "header1", + }, + "example2": {"value": "header2"}, + }, + "name": "data", + "in": "header", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/cookie_example/": { + "get": { + "summary": "Cookie Example", + "operationId": "cookie_example_cookie_example__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Data", "type": "string"}, + "example": "cookie1", + "name": "data", + "in": "cookie", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/cookie_examples/": { + "get": { + "summary": "Cookie Examples", + "operationId": "cookie_examples_cookie_examples__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Data", "type": "string"}, + "examples": { + "example1": { + "summary": "cookie example 1", + "value": "cookie1", + }, + "example2": {"value": "cookie2"}, + }, + "name": "data", + "in": "cookie", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/cookie_example_examples/": { + "get": { + "summary": "Cookie Example Examples", + "operationId": "cookie_example_examples_cookie_example_examples__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Data", "type": "string"}, + "examples": { + "example1": { + "summary": "Qeury example 1", + "value": "cookie1", + }, + "example2": {"value": "cookie2"}, + }, + "name": "data", + "in": "cookie", + } + ], + "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": ["data"], + "type": "object", + "properties": {"data": {"title": "Data", "type": "string"}}, + "example": {"data": "Data in schema_extra"}, + }, + "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"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + """ + Test that example overrides work: + + * pydantic model schema_extra is included + * Body(example={}) overrides schema_extra in pydantic model + * Body(examples{}) overrides Body(example={}) and schema_extra in pydantic model + """ + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_call_api(): + response = client.post("/schema_extra/", json={"data": "Foo"}) + assert response.status_code == 200, response.text + response = client.post("/example/", json={"data": "Foo"}) + assert response.status_code == 200, response.text + response = client.post("/examples/", json={"data": "Foo"}) + assert response.status_code == 200, response.text + response = client.post("/example_examples/", json={"data": "Foo"}) + assert response.status_code == 200, response.text + response = client.get("/path_example/foo") + assert response.status_code == 200, response.text + response = client.get("/path_examples/foo") + assert response.status_code == 200, response.text + response = client.get("/path_example_examples/foo") + assert response.status_code == 200, response.text + response = client.get("/query_example/") + assert response.status_code == 200, response.text + response = client.get("/query_examples/") + assert response.status_code == 200, response.text + response = client.get("/query_example_examples/") + assert response.status_code == 200, response.text + response = client.get("/header_example/") + assert response.status_code == 200, response.text + response = client.get("/header_examples/") + assert response.status_code == 200, response.text + response = client.get("/header_example_examples/") + assert response.status_code == 200, response.text + response = client.get("/cookie_example/") + assert response.status_code == 200, response.text + response = client.get("/cookie_examples/") + assert response.status_code == 200, response.text + response = client.get("/cookie_example_examples/") + assert response.status_code == 200, response.text diff --git a/tests/test_tutorial/test_schema_extra_example/__init__.py b/tests/test_tutorial/test_schema_extra_example/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py new file mode 100644 index 000000000..89f5b66fd --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py @@ -0,0 +1,134 @@ +from fastapi.testclient import TestClient + +from docs_src.schema_extra_example.tutorial004 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "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": {"$ref": "#/components/schemas/Item"}, + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "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"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +# Test required and embedded body parameters with no bodies sent +def test_post_body_example(): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200