To see what exactly you can include in the responses, you can check these sections in the OpenAPI specification:
-* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" class="external-link" target="_blank">OpenAPI Responses Object</a>, it includes the `Response Object`.
-* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" class="external-link" target="_blank">OpenAPI Response Object</a>, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`.
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responsesObject" class="external-link" target="_blank">OpenAPI Responses Object</a>, it includes the `Response Object`.
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responseObject" class="external-link" target="_blank">OpenAPI Response Object</a>, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`.
```JSON hl_lines="4-8"
{
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
// More stuff here
"servers": [
{
```JSON hl_lines="5-7"
{
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
// More stuff here
"servers": [
{
* `title`: The OpenAPI title, shown in the docs.
* `version`: The version of your API, e.g. `2.5.0`.
-* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.0.2`.
-* `description`: The description of your API.
+* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`.
+* `summary`: A short summary of the API.
+* `description`: The description of your API, this can include markdown and will be shown in the docs.
* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`.
+!!! info
+ The parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above.
+
## Overriding the defaults
Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need.
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
-```Python hl_lines="2 15-20"
+```Python hl_lines="2 15-21"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
-```Python hl_lines="21-23"
+```Python hl_lines="22-24"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
It will be generated only once, and then the same cached schema will be used for the next requests.
-```Python hl_lines="13-14 24-25"
+```Python hl_lines="13-14 25-26"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
Now you can replace the `.openapi()` method with your new function.
-```Python hl_lines="28"
+```Python hl_lines="29"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
There are 2 main differences from a normal *path operation*:
* It doesn't need to have any actual code, because your app will never call this code. It's only used to document the *external API*. So, the function could just have `pass`.
-* The *path* can contain an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> (see more below) where it can use variables with parameters and parts of the original request sent to *your API*.
+* The *path* can contain an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> (see more below) where it can use variables with parameters and parts of the original request sent to *your API*.
### The callback path expression
-The callback *path* can have an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> that can contain parts of the original request sent to *your API*.
+The callback *path* can have an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> that can contain parts of the original request sent to *your API*.
In this case, it's the `str`:
--- /dev/null
+# OpenAPI Webhooks
+
+There are cases where you want to tell your API **users** that your app could call *their* app (sending a request) with some data, normally to **notify** of some type of **event**.
+
+This means that instead of the normal process of your users sending requests to your API, it's **your API** (or your app) that could **send requests to their system** (to their API, their app).
+
+This is normally called a **webhook**.
+
+## Webhooks steps
+
+The process normally is that **you define** in your code what is the message that you will send, the **body of the request**.
+
+You also define in some way at which **moments** your app will send those requests or events.
+
+And **your users** define in some way (for example in a web dashboard somewhere) the **URL** where your app should send those requests.
+
+All the **logic** about how to register the URLs for webhooks and the code to actually send those requests is up to you. You write it however you want to in **your own code**.
+
+## Documenting webhooks with **FastAPI** and OpenAPI
+
+With **FastAPI**, using OpenAPI, you can define the names of these webhooks, the types of HTTP operations that your app can send (e.g. `POST`, `PUT`, etc.) and the request **bodies** that your app would send.
+
+This can make it a lot easier for your users to **implement their APIs** to receive your **webhook** requests, they might even be able to autogenerate some of their own API code.
+
+!!! info
+ Webhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0` and above.
+
+## An app with webhooks
+
+When you create a **FastAPI** application, there is a `webhooks` attribute that you can use to define *webhooks*, the same way you would define *path operations*, for example with `@app.webhooks.post()`.
+
+```Python hl_lines="9-13 36-53"
+{!../../../docs_src/openapi_webhooks/tutorial001.py!}
+```
+
+The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**.
+
+!!! info
+ The `app.webhooks` object is actually just an `APIRouter`, the same type you would use when structuring your app with multiple files.
+
+Notice that with webhooks you are actually not declaring a *path* (like `/items/`), the text you pass there is just an **identifier** of the webhook (the name of the event), for example in `@app.webhooks.post("new-subscription")`, the webhook name is `new-subscription`.
+
+This is because it is expected that **your users** would define the actual **URL path** where they want to receive the webhook request in some other way (e.g. a web dashboard).
+
+### Check the docs
+
+Now you can start your app with Uvicorn and go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
+
+You will see your docs have the normal *path operations* and now also some **webhooks**:
+
+<img src="/img/tutorial/openapi-webhooks/image01.png">
```JSON hl_lines="22"
{
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
```JSON
{
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
| Parameter | Type | Description |
|------------|------|-------------|
| `title` | `str` | The title of the API. |
+| `summary` | `str` | A short summary of the API. <small>Available since OpenAPI 3.1.0, FastAPI 0.99.0.</small> |
| `description` | `str` | A short description of the API. It can use Markdown. |
| `version` | `string` | The version of the API. This is the version of your own application, not of OpenAPI. For example `2.5.0`. |
| `terms_of_service` | `str` | A URL to the Terms of Service for the API. If provided, this has to be a URL. |
| `contact` | `dict` | The contact information for the exposed API. It can contain several fields. <details><summary><code>contact</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>The identifying name of the contact person/organization.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>The URL pointing to the contact information. MUST be in the format of a URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>The email address of the contact person/organization. MUST be in the format of an email address.</td></tr></tbody></table></details> |
-| `license_info` | `dict` | The license information for the exposed API. It can contain several fields. <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>REQUIRED</strong> (if a <code>license_info</code> is set). The license name used for the API.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>A URL to the license used for the API. MUST be in the format of a URL.</td></tr></tbody></table></details> |
+| `license_info` | `dict` | The license information for the exposed API. It can contain several fields. <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>REQUIRED</strong> (if a <code>license_info</code> is set). The license name used for the API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>An <a href="https://spdx.dev/spdx-specification-21-web-version/#h.jxpfx0ykyb60" class="external-link" target="_blank">SPDX</a> license expression for the API. The <code>identifier</code> field is mutually exclusive of the <code>url</code> field. <small>Available since OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>A URL to the license used for the API. MUST be in the format of a URL.</td></tr></tbody></table></details> |
You can set them as follows:
-```Python hl_lines="3-16 19-31"
+```Python hl_lines="3-16 19-32"
{!../../../docs_src/metadata/tutorial001.py!}
```
<img src="/img/tutorial/metadata/image01.png">
+## License identifier
+
+Since OpenAPI 3.1.0 and FastAPI 0.99.0, you can also set the `license_info` with an `identifier` instead of a `url`.
+
+For example:
+
+```Python hl_lines="31"
+{!../../../docs_src/metadata/tutorial001_1.py!}
+```
+
## Metadata for tags
You can also add additional metadata for the different tags used to group your path operations with the parameter `openapi_tags`.
## Standards-based benefits, alternative documentation
-And because the generated schema is from the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a> standard, there are many compatible tools.
+And because the generated schema is from the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a> standard, there are many compatible tools.
Because of this, **FastAPI** itself provides an alternative API documentation (using ReDoc), which you can access at <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>:
## Pydantic `schema_extra`
-You can declare an `example` for a Pydantic model using `Config` and `schema_extra`, as described in <a href="https://pydantic-docs.helpmanual.io/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic's docs: Schema customization</a>:
+You can declare `examples` for a Pydantic model using `Config` and `schema_extra`, as described in <a href="https://pydantic-docs.helpmanual.io/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic's docs: Schema customization</a>:
=== "Python 3.10+"
- ```Python hl_lines="13-21"
+ ```Python hl_lines="13-23"
{!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!}
```
=== "Python 3.6+"
- ```Python hl_lines="15-23"
+ ```Python hl_lines="15-25"
{!> ../../../docs_src/schema_extra_example/tutorial001.py!}
```
For example you could use it to add metadata for a frontend user interface, etc.
-## `Field` additional arguments
+!!! info
+ OpenAPI 3.1.0 (used since FastAPI 0.99.0) added support for `examples`, which is part of the **JSON Schema** standard.
+
+ Before that, it only supported the keyword `example` with a single example. That is still supported by OpenAPI 3.1.0, but is deprecated and is not part of the JSON Schema standard. So you are encouraged to migrate `example` to `examples`. 🤓
+
+ You can read more at the end of this page.
-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.
+## `Field` additional arguments
-You can use this to add `example` for each field:
+When using `Field()` with Pydantic models, you can also declare additional `examples`:
=== "Python 3.10+"
{!> ../../../docs_src/schema_extra_example/tutorial002.py!}
```
-!!! warning
- Keep in mind that those extra arguments passed won't add any validation, only extra information, for documentation purposes.
-
-## `example` and `examples` in OpenAPI
+## `examples` in OpenAPI
When using any of:
* `Form()`
* `File()`
-you can also declare a data `example` or a group of `examples` with additional information that will be added to **OpenAPI**.
+you can also declare a group of `examples` with additional information that will be added to **OpenAPI**.
-### `Body` with `example`
+### `Body` with `examples`
-Here we pass an `example` of the data expected in `Body()`:
+Here we pass `examples` containing one example of the data expected in `Body()`:
=== "Python 3.10+"
- ```Python hl_lines="22-27"
+ ```Python hl_lines="22-29"
{!> ../../../docs_src/schema_extra_example/tutorial003_an_py310.py!}
```
=== "Python 3.9+"
- ```Python hl_lines="22-27"
+ ```Python hl_lines="22-29"
{!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
- ```Python hl_lines="23-28"
+ ```Python hl_lines="23-30"
{!> ../../../docs_src/schema_extra_example/tutorial003_an.py!}
```
!!! tip
Prefer to use the `Annotated` version if possible.
- ```Python hl_lines="18-23"
+ ```Python hl_lines="18-25"
{!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
```
!!! tip
Prefer to use the `Annotated` version if possible.
- ```Python hl_lines="20-25"
+ ```Python hl_lines="20-27"
{!> ../../../docs_src/schema_extra_example/tutorial003.py!}
```
### `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`.
+You can of course also pass multiple `examples`:
=== "Python 3.10+"
## Technical Details
+!!! tip
+ If you are already using **FastAPI** version **0.99.0 or above**, you can probably **skip** these details.
+
+ They are more relevant for older versions, before OpenAPI 3.1.0 was available.
+
+ You can consider this a brief OpenAPI and JSON Schema **history lesson**. 🤓
+
!!! warning
These are very technical details about the standards **JSON Schema** and **OpenAPI**.
If the ideas above already work for you, that might be 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.
+Before OpenAPI 3.1.0, OpenAPI used an older and modified version of **JSON Schema**.
-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 didn't have `examples`, so OpenAPI added it's own `example` field to its own modified version.
+
+OpenAPI also added `example` and `examples` fields to other parts of the specification:
+
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object" class="external-link" target="_blank">`Parameter Object` (in the specification)</a> that was used by FastAPI's:
+ * `Path()`
+ * `Query()`
+ * `Header()`
+ * `Cookie()`
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object" class="external-link" target="_blank">`Request Body Object`, in the field `content`, on the `Media Type Object` (in the specification)</a> that was used by FastAPI's:
+ * `Body()`
+ * `File()`
+ * `Form()`
-**JSON Schema** doesn't really have a field `example` in the standards. Recent versions of JSON Schema define a field <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a>, but OpenAPI 3.0.3 is based on an older version of JSON Schema that didn't have `examples`.
+### OpenAPI's `examples` field
-So, OpenAPI 3.0.3 defined its own <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#fixed-fields-20" class="external-link" target="_blank">`example`</a> 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).
+The shape of this field `examples` from OpenAPI is 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`.
+
+This applies to those other parts of the OpenAPI specification apart from JSON Schema.
+
+### JSON Schema's `examples` field
+
+But then JSON Schema added an <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a> field to a new version of the specification.
+
+And then the new OpenAPI 3.1.0 was based on the latest version (JSON Schema 2020-12) that included this new field `examples`.
+
+And now this new `examples` field takes precedence over the old single (and custom) `example` field, that is now deprecated.
+
+This new `examples` field in JSON Schema is **just a `list`** of examples, not a dict with extra metadata as in the other places in OpenAPI (described above).
+
+!!! info
+ Even after OpenAPI 3.1.0 was released with this new simpler integration with JSON Schema, for a while, Swagger UI, the tool that provides the automatic docs, didn't support OpenAPI 3.1.0 (it does since version 5.0.0 🎉).
+
+ Because of that, versions of FastAPI previous to 0.99.0 still used versions of OpenAPI lower than 3.1.0.
+
+### Pydantic and FastAPI `examples`
+
+When you add `examples` inside of a Pydantic model, using `schema_extra` or `Field(examples=["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.
-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.
+In versions of FastAPI before 0.99.0 (0.99.0 and above use the newer OpenAPI 3.1.0) when you used `example` or `examples` with any of the other utilities (`Query()`, `Body()`, etc.) those examples were not added to the JSON Schema that describes that data (not even to OpenAPI's own version of JSON Schema), they were added directly to the *path operation* declaration in OpenAPI (outside the parts of OpenAPI that use JSON Schema).
-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).
+But now that FastAPI 0.99.0 and above uses OpenAPI 3.1.0, that uses JSON Schema 2020-12, and Swagger UI 5.0.0 and above, everything is more consistent and the examples are included in JSON Schema.
-For `Path()`, `Query()`, `Header()`, and `Cookie()`, the `example` or `examples` are added to the <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#parameter-object" class="external-link" target="_blank">OpenAPI definition, to the `Parameter Object` (in the specification)</a>.
+### Summary
-And for `Body()`, `File()`, and `Form()`, the `example` or `examples` are equivalently added to the <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#mediaTypeObject" class="external-link" target="_blank">OpenAPI definition, to the `Request Body Object`, in the field `content`, on the `Media Type Object` (in the specification)</a>.
+I used to say I didn't like history that much... and look at me now giving "tech history" lessons. 😅
-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.
+In short, **upgrade to FastAPI 0.99.0 or above**, and things are much **simpler, consistent, and intuitive**, and you don't have to know all these historic details. 😎
- advanced/conditional-openapi.md
- advanced/extending-openapi.md
- advanced/openapi-callbacks.md
+ - advanced/openapi-webhooks.md
- advanced/wsgi.md
- advanced/generate-clients.md
- async.md
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
- description="This is a very custom OpenAPI schema",
+ summary="This is a very custom OpenAPI schema",
+ description="Here's a longer description of the custom **OpenAPI** schema",
routes=app.routes,
)
openapi_schema["info"]["x-logo"] = {
app = FastAPI(
title="ChimichangApp",
description=description,
+ summary="Deadpool's favorite app. Nuff said.",
version="0.0.1",
terms_of_service="http://example.com/terms/",
contact={
--- /dev/null
+from fastapi import FastAPI
+
+description = """
+ChimichangApp API helps you do awesome stuff. 🚀
+
+## Items
+
+You can **read items**.
+
+## Users
+
+You will be able to:
+
+* **Create users** (_not implemented_).
+* **Read users** (_not implemented_).
+"""
+
+app = FastAPI(
+ title="ChimichangApp",
+ description=description,
+ summary="Deadpool's favorite app. Nuff said.",
+ version="0.0.1",
+ terms_of_service="http://example.com/terms/",
+ contact={
+ "name": "Deadpoolio the Amazing",
+ "url": "http://x-force.example.com/contact/",
+ "email": "dp@x-force.example.com",
+ },
+ license_info={
+ "name": "Apache 2.0",
+ "identifier": "MIT",
+ },
+)
+
+
+@app.get("/items/")
+async def read_items():
+ return [{"name": "Katana"}]
--- /dev/null
+from datetime import datetime
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Subscription(BaseModel):
+ username: str
+ montly_fee: float
+ start_date: datetime
+
+
+@app.webhooks.post("new-subscription")
+def new_subscription(body: Subscription):
+ """
+ When a new user subscribes to your service we'll send you a POST request with this
+ data to the URL that you register for the event `new-subscription` in the dashboard.
+ """
+
+
+@app.get("/users/")
+def read_users():
+ return ["Rick", "Morty"]
class Config:
schema_extra = {
- "example": {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- }
+ "examples": [
+ {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ }
+ ]
}
class Config:
schema_extra = {
- "example": {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- }
+ "examples": [
+ {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ }
+ ]
}
class Item(BaseModel):
- name: str = Field(example="Foo")
- description: Union[str, None] = Field(default=None, example="A very nice Item")
- price: float = Field(example=35.4)
- tax: Union[float, None] = Field(default=None, example=3.2)
+ name: str = Field(examples=["Foo"])
+ description: Union[str, None] = Field(default=None, examples=["A very nice Item"])
+ price: float = Field(examples=[35.4])
+ tax: Union[float, None] = Field(default=None, examples=[3.2])
@app.put("/items/{item_id}")
class Item(BaseModel):
- name: str = Field(example="Foo")
- description: str | None = Field(default=None, example="A very nice Item")
- price: float = Field(example=35.4)
- tax: float | None = Field(default=None, example=3.2)
+ name: str = Field(examples=["Foo"])
+ description: str | None = Field(default=None, examples=["A very nice Item"])
+ price: float = Field(examples=[35.4])
+ tax: float | None = Field(default=None, examples=[3.2])
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: Item = Body(
- example={
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- },
+ examples=[
+ {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ }
+ ],
),
):
results = {"item_id": item_id, "item": item}
item: Annotated[
Item,
Body(
- example={
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- },
+ examples=[
+ {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ }
+ ],
),
],
):
item: Annotated[
Item,
Body(
- example={
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- },
+ examples=[
+ {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ }
+ ],
),
],
):
item: Annotated[
Item,
Body(
- example={
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- },
+ examples=[
+ {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ }
+ ],
),
],
):
async def update_item(
item_id: int,
item: Item = Body(
- example={
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- },
+ examples=[
+ {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ }
+ ],
),
):
results = {"item_id": item_id, "item": item}
*,
item_id: int,
item: Item = Body(
- examples={
- "normal": {
+ examples=[
+ {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"tax": 3.2,
},
},
- "converted": {
+ {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"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}
item: Annotated[
Item,
Body(
- examples={
- "normal": {
+ examples=[
+ {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"tax": 3.2,
},
},
- "converted": {
+ {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"price": "35.4",
},
},
- "invalid": {
+ {
"summary": "Invalid data is rejected with an error",
"value": {
"name": "Baz",
"price": "thirty five point four",
},
},
- },
+ ],
),
],
):
item: Annotated[
Item,
Body(
- examples={
- "normal": {
+ examples=[
+ {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"tax": 3.2,
},
},
- "converted": {
+ {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"price": "35.4",
},
},
- "invalid": {
+ {
"summary": "Invalid data is rejected with an error",
"value": {
"name": "Baz",
"price": "thirty five point four",
},
},
- },
+ ],
),
],
):
item: Annotated[
Item,
Body(
- examples={
- "normal": {
+ examples=[
+ {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"tax": 3.2,
},
},
- "converted": {
+ {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"price": "35.4",
},
},
- "invalid": {
+ {
"summary": "Invalid data is rejected with an error",
"value": {
"name": "Baz",
"price": "thirty five point four",
},
},
- },
+ ],
),
],
):
*,
item_id: int,
item: Item = Body(
- examples={
- "normal": {
+ examples=[
+ {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"tax": 3.2,
},
},
- "converted": {
+ {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"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}
debug: bool = False,
routes: Optional[List[BaseRoute]] = None,
title: str = "FastAPI",
+ summary: Optional[str] = None,
description: str = "",
version: str = "0.1.0",
openapi_url: Optional[str] = "/openapi.json",
root_path_in_servers: bool = True,
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
callbacks: Optional[List[BaseRoute]] = None,
+ webhooks: Optional[routing.APIRouter] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
swagger_ui_parameters: Optional[Dict[str, Any]] = None,
) -> None:
self.debug = debug
self.title = title
+ self.summary = summary
self.description = description
self.version = version
self.terms_of_service = terms_of_service
self.swagger_ui_parameters = swagger_ui_parameters
self.servers = servers or []
self.extra = extra
- self.openapi_version = "3.0.2"
+ self.openapi_version = "3.1.0"
self.openapi_schema: Optional[Dict[str, Any]] = None
if self.openapi_url:
assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'"
"automatic. Check the docs at "
"https://fastapi.tiangolo.com/advanced/sub-applications/"
)
+ self.webhooks = webhooks or routing.APIRouter()
self.root_path = root_path or openapi_prefix
self.state: State = State()
self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {}
title=self.title,
version=self.version,
openapi_version=self.openapi_version,
+ summary=self.summary,
description=self.description,
terms_of_service=self.terms_of_service,
contact=self.contact,
license_info=self.license_info,
routes=self.routes,
+ webhooks=self.webhooks.routes,
tags=self.openapi_tags,
servers=self.servers,
)
*,
openapi_url: str,
title: str,
- swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js",
- swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css",
+ swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js",
+ swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css",
swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
oauth2_redirect_url: Optional[str] = None,
init_oauth: Optional[Dict[str, Any]] = None,
from enum import Enum
-from typing import Any, Callable, Dict, Iterable, List, Optional, Union
+from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Union
from fastapi.logger import logger
from pydantic import AnyUrl, BaseModel, Field
-from typing_extensions import Literal
+from typing_extensions import Annotated, Literal
+from typing_extensions import deprecated as typing_deprecated
try:
import email_validator # type: ignore
class License(BaseModel):
name: str
+ identifier: Optional[str] = None
url: Optional[AnyUrl] = None
class Config:
class Info(BaseModel):
title: str
+ summary: Optional[str] = None
description: Optional[str] = None
termsOfService: Optional[str] = None
contact: Optional[Contact] = None
class ServerVariable(BaseModel):
- enum: Optional[List[str]] = None
+ enum: Annotated[Optional[List[str]], Field(min_items=1)] = None
default: str
description: Optional[str] = None
class Schema(BaseModel):
+ # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu
+ # Core Vocabulary
+ schema_: Optional[str] = Field(default=None, alias="$schema")
+ vocabulary: Optional[str] = Field(default=None, alias="$vocabulary")
+ id: Optional[str] = Field(default=None, alias="$id")
+ anchor: Optional[str] = Field(default=None, alias="$anchor")
+ dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor")
ref: Optional[str] = Field(default=None, alias="$ref")
- title: Optional[str] = None
- multipleOf: Optional[float] = None
+ dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef")
+ defs: Optional[Dict[str, "Schema"]] = Field(default=None, alias="$defs")
+ comment: Optional[str] = Field(default=None, alias="$comment")
+ # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s
+ # A Vocabulary for Applying Subschemas
+ allOf: Optional[List["Schema"]] = None
+ anyOf: Optional[List["Schema"]] = None
+ oneOf: Optional[List["Schema"]] = None
+ not_: Optional["Schema"] = Field(default=None, alias="not")
+ if_: Optional["Schema"] = Field(default=None, alias="if")
+ then: Optional["Schema"] = None
+ else_: Optional["Schema"] = Field(default=None, alias="else")
+ dependentSchemas: Optional[Dict[str, "Schema"]] = None
+ prefixItems: Optional[List["Schema"]] = None
+ items: Optional[Union["Schema", List["Schema"]]] = None
+ contains: Optional["Schema"] = None
+ properties: Optional[Dict[str, "Schema"]] = None
+ patternProperties: Optional[Dict[str, "Schema"]] = None
+ additionalProperties: Optional["Schema"] = None
+ propertyNames: Optional["Schema"] = None
+ unevaluatedItems: Optional["Schema"] = None
+ unevaluatedProperties: Optional["Schema"] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural
+ # A Vocabulary for Structural Validation
+ type: Optional[str] = None
+ enum: Optional[List[Any]] = None
+ const: Optional[Any] = None
+ multipleOf: Optional[float] = Field(default=None, gt=0)
maximum: Optional[float] = None
exclusiveMaximum: Optional[float] = None
minimum: Optional[float] = None
maxItems: Optional[int] = Field(default=None, ge=0)
minItems: Optional[int] = Field(default=None, ge=0)
uniqueItems: Optional[bool] = None
+ maxContains: Optional[int] = Field(default=None, ge=0)
+ minContains: Optional[int] = Field(default=None, ge=0)
maxProperties: Optional[int] = Field(default=None, ge=0)
minProperties: Optional[int] = Field(default=None, ge=0)
required: Optional[List[str]] = None
- enum: Optional[List[Any]] = None
- type: Optional[str] = None
- allOf: Optional[List["Schema"]] = None
- oneOf: Optional[List["Schema"]] = None
- anyOf: Optional[List["Schema"]] = None
- not_: Optional["Schema"] = Field(default=None, alias="not")
- items: Optional[Union["Schema", List["Schema"]]] = None
- properties: Optional[Dict[str, "Schema"]] = None
- additionalProperties: Optional[Union["Schema", Reference, bool]] = None
- description: Optional[str] = None
+ dependentRequired: Optional[Dict[str, Set[str]]] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c
+ # Vocabularies for Semantic Content With "format"
format: Optional[str] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten
+ # A Vocabulary for the Contents of String-Encoded Data
+ contentEncoding: Optional[str] = None
+ contentMediaType: Optional[str] = None
+ contentSchema: Optional["Schema"] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta
+ # A Vocabulary for Basic Meta-Data Annotations
+ title: Optional[str] = None
+ description: Optional[str] = None
default: Optional[Any] = None
- nullable: Optional[bool] = None
- discriminator: Optional[Discriminator] = None
+ deprecated: Optional[bool] = None
readOnly: Optional[bool] = None
writeOnly: Optional[bool] = None
+ examples: Optional[List[Any]] = None
+ # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object
+ # Schema Object
+ discriminator: Optional[Discriminator] = None
xml: Optional[XML] = None
externalDocs: Optional[ExternalDocumentation] = None
- example: Optional[Any] = None
- deprecated: Optional[bool] = None
+ example: Annotated[
+ Optional[Any],
+ typing_deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = None
class Config:
extra: str = "allow"
parameters: Optional[List[Union[Parameter, Reference]]] = None
requestBody: Optional[Union[RequestBody, Reference]] = None
# Using Any for Specification Extensions
- responses: Dict[str, Union[Response, Any]]
+ responses: Optional[Dict[str, Union[Response, Any]]] = None
callbacks: Optional[Dict[str, Union[Dict[str, "PathItem"], Reference]]] = None
deprecated: Optional[bool] = None
security: Optional[List[Dict[str, List[str]]]] = None
links: Optional[Dict[str, Union[Link, Reference]]] = None
# Using Any for Specification Extensions
callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None
+ pathItems: Optional[Dict[str, Union[PathItem, Reference]]] = None
class Config:
extra = "allow"
class OpenAPI(BaseModel):
openapi: str
info: Info
+ jsonSchemaDialect: Optional[str] = None
servers: Optional[List[Server]] = None
# Using Any for Specification Extensions
- paths: Dict[str, Union[PathItem, Any]]
+ paths: Optional[Dict[str, Union[PathItem, Any]]] = None
+ webhooks: Optional[Dict[str, Union[PathItem, Reference]]] = None
components: Optional[Components] = None
security: Optional[List[Dict[str, List[str]]]] = None
tags: Optional[List[Tag]] = None
}
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:
+ if field_info.example != Undefined:
parameter["example"] = jsonable_encoder(field_info.example)
if field_info.deprecated:
parameter["deprecated"] = field_info.deprecated
if required:
request_body_oai["required"] = required
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:
+ if 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
*,
title: str,
version: str,
- openapi_version: str = "3.0.2",
+ openapi_version: str = "3.1.0",
+ summary: Optional[str] = None,
description: Optional[str] = None,
routes: Sequence[BaseRoute],
+ webhooks: Optional[Sequence[BaseRoute]] = None,
tags: Optional[List[Dict[str, Any]]] = None,
servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
terms_of_service: Optional[str] = None,
license_info: Optional[Dict[str, Union[str, Any]]] = None,
) -> Dict[str, Any]:
info: Dict[str, Any] = {"title": title, "version": version}
+ if summary:
+ info["summary"] = summary
if description:
info["description"] = description
if terms_of_service:
output["servers"] = servers
components: Dict[str, Dict[str, Any]] = {}
paths: Dict[str, Dict[str, Any]] = {}
+ webhook_paths: Dict[str, Dict[str, Any]] = {}
operation_ids: Set[str] = set()
- flat_models = get_flat_models_from_routes(routes)
+ flat_models = get_flat_models_from_routes(list(routes or []) + list(webhooks or []))
model_name_map = get_model_name_map(flat_models)
definitions = get_model_definitions(
flat_models=flat_models, model_name_map=model_name_map
)
- for route in routes:
+ for route in routes or []:
if isinstance(route, routing.APIRoute):
result = get_openapi_path(
route=route, model_name_map=model_name_map, operation_ids=operation_ids
)
if path_definitions:
definitions.update(path_definitions)
+ for webhook in webhooks or []:
+ if isinstance(webhook, routing.APIRoute):
+ result = get_openapi_path(
+ route=webhook,
+ model_name_map=model_name_map,
+ operation_ids=operation_ids,
+ )
+ if result:
+ path, security_schemes, path_definitions = result
+ if path:
+ webhook_paths.setdefault(webhook.path_format, {}).update(path)
+ if security_schemes:
+ components.setdefault("securitySchemes", {}).update(
+ security_schemes
+ )
+ if path_definitions:
+ definitions.update(path_definitions)
if definitions:
components["schemas"] = {k: definitions[k] for k in sorted(definitions)}
if components:
output["components"] = components
output["paths"] = paths
+ if webhook_paths:
+ output["webhooks"] = webhook_paths
if tags:
output["tags"] = tags
return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore
-from typing import Any, Callable, Dict, Optional, Sequence
+from typing import Any, Callable, List, Optional, Sequence
from fastapi import params
from pydantic.fields import Undefined
+from typing_extensions import Annotated, deprecated
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,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
**extra: Any,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
**extra: Any,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
**extra: Any,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
**extra: Any,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
**extra: Any,
) -> Any:
return params.Body(
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
**extra: Any,
) -> Any:
return params.Form(
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
**extra: Any,
) -> Any:
return params.File(
+import warnings
from enum import Enum
-from typing import Any, Callable, Dict, Optional, Sequence
+from typing import Any, Callable, List, Optional, Sequence
from pydantic.fields import FieldInfo, Undefined
+from typing_extensions import Annotated, deprecated
class ParamTypes(Enum):
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
**extra: Any,
):
self.deprecated = deprecated
+ if example is not Undefined:
+ warnings.warn(
+ "`example` has been depreacated, please use `examples` instead",
+ category=DeprecationWarning,
+ stacklevel=1,
+ )
self.example = example
- self.examples = examples
self.include_in_schema = include_in_schema
+ extra_kwargs = {**extra}
+ if examples:
+ extra_kwargs["examples"] = examples
super().__init__(
default=default,
alias=alias,
min_length=min_length,
max_length=max_length,
regex=regex,
- **extra,
+ **extra_kwargs,
)
def __repr__(self) -> str:
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
**extra: Any,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
**extra: Any,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
**extra: Any,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
**extra: Any,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
**extra: Any,
):
self.embed = embed
self.media_type = media_type
+ if example is not Undefined:
+ warnings.warn(
+ "`example` has been depreacated, please use `examples` instead",
+ category=DeprecationWarning,
+ stacklevel=1,
+ )
self.example = example
- self.examples = examples
+ extra_kwargs = {**extra}
+ if examples is not None:
+ extra_kwargs["examples"] = examples
super().__init__(
default=default,
alias=alias,
min_length=min_length,
max_length=max_length,
regex=regex,
- **extra,
+ **extra_kwargs,
)
def __repr__(self) -> str:
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
**extra: Any,
):
super().__init__(
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
- example: Any = Undefined,
- examples: Optional[Dict[str, Any]] = None,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = Undefined,
**extra: Any,
):
super().__init__(
dependencies = [
"starlette>=0.27.0,<0.28.0",
"pydantic>=1.7.4,!=1.8,!=1.8.1,<2.0.0",
+ "typing-extensions>=4.5.0"
]
dynamic = ["version"]
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/foo": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
openapi_schema = {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/a": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/a/{id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/a/{id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/a": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/a": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/default": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/api_route": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/a/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/with-duplicates": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/app": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
}
},
"info": {"title": "FastAPI", "version": "0.1.0"},
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"paths": {
"/foo": {
"get": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/model/{name}": {
response = client.get("/openapi.json")
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/product": {
assert issubclass(w[-1].category, UserWarning)
assert "Duplicate Operation ID" in str(w[-1].message)
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/override1": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/a/compute": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"servers": [
{"url": "/", "description": "Default, relative server"},
response = client.get("/openapi.json")
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/{user_id}": {
openapi_schema = {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/hidden_cookie": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
}
},
"info": {"title": "FastAPI", "version": "0.1.0"},
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"paths": {
"/": {
"get": {
}
},
"info": {"title": "FastAPI", "version": "0.1.0"},
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"paths": {
"/{repeated_alias}": {
"get": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/{id}": {
assert response.status_code == 200, response.text
# insert_assert(response.json())
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/products": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/dict": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/a": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/a": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/no_response_model-no_annotation-return_model": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/valid1": {
from typing import Union
+import pytest
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": "Overridden 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 overridden",
-# 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_overridden",
- examples={
- "example1": {"summary": "item ID summary", "value": "item_1"},
- "example2": {"value": "item_2"},
- },
- ),
-):
- return item_id
-
-
-@app.get("/query_example/")
-def query_example(
- data: Union[str, None] = Query(
- default=None,
- example="query1",
- ),
-):
- return data
-
-
-@app.get("/query_examples/")
-def query_examples(
- data: Union[str, None] = Query(
- default=None,
- examples={
- "example1": {"summary": "Query example 1", "value": "query1"},
- "example2": {"value": "query2"},
- },
- ),
-):
- return data
-
-
-@app.get("/query_example_examples/")
-def query_example_examples(
- data: Union[str, None] = Query(
- default=None,
- example="query_overridden",
- examples={
- "example1": {"summary": "Query example 1", "value": "query1"},
- "example2": {"value": "query2"},
- },
- ),
-):
- return data
-
-
-@app.get("/header_example/")
-def header_example(
- data: Union[str, None] = Header(
- default=None,
- example="header1",
- ),
-):
- return data
-
-
-@app.get("/header_examples/")
-def header_examples(
- data: Union[str, None] = Header(
- default=None,
- examples={
- "example1": {"summary": "header example 1", "value": "header1"},
- "example2": {"value": "header2"},
- },
- ),
-):
- return data
-
-
-@app.get("/header_example_examples/")
-def header_example_examples(
- data: Union[str, None] = Header(
- default=None,
- example="header_overridden",
- examples={
- "example1": {"summary": "Query example 1", "value": "header1"},
- "example2": {"value": "header2"},
- },
- ),
-):
- return data
-
-
-@app.get("/cookie_example/")
-def cookie_example(
- data: Union[str, None] = Cookie(
- default=None,
- example="cookie1",
- ),
-):
- return data
-
-
-@app.get("/cookie_examples/")
-def cookie_examples(
- data: Union[str, None] = Cookie(
- default=None,
- examples={
- "example1": {"summary": "cookie example 1", "value": "cookie1"},
- "example2": {"value": "cookie2"},
- },
- ),
-):
- return data
-
-
-@app.get("/cookie_example_examples/")
-def cookie_example_examples(
- data: Union[str, None] = Cookie(
- default=None,
- example="cookie_overridden",
- examples={
- "example1": {"summary": "Query example 1", "value": "cookie1"},
- "example2": {"value": "cookie2"},
- },
- ),
-):
- return data
-
-
-client = TestClient(app)
+def create_app():
+ 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
+
+ with pytest.warns(DeprecationWarning):
+
+ @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=[
+ {"data": "Data in Body examples, example1"},
+ {"data": "Data in Body examples, example2"},
+ ],
+ )
+ ):
+ return item
+
+ with pytest.warns(DeprecationWarning):
+
+ @app.post("/example_examples/")
+ def example_examples(
+ item: Item = Body(
+ example={"data": "Overridden example"},
+ examples=[
+ {"data": "examples example_examples 1"},
+ {"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 overridden",
+ # examples={
+ # "example1": {"summary": "last name summary", "value": "Doe"},
+ # "example2": {"value": "Doesn't"},
+ # },
+ # ),
+ # ):
+ # return lastname
+
+ with pytest.warns(DeprecationWarning):
+
+ @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=["item_1", "item_2"],
+ ),
+ ):
+ return item_id
+
+ with pytest.warns(DeprecationWarning):
+
+ @app.get("/path_example_examples/{item_id}")
+ def path_example_examples(
+ item_id: str = Path(
+ example="item_overridden",
+ examples=["item_1", "item_2"],
+ ),
+ ):
+ return item_id
+
+ with pytest.warns(DeprecationWarning):
+
+ @app.get("/query_example/")
+ def query_example(
+ data: Union[str, None] = Query(
+ default=None,
+ example="query1",
+ ),
+ ):
+ return data
+
+ @app.get("/query_examples/")
+ def query_examples(
+ data: Union[str, None] = Query(
+ default=None,
+ examples=["query1", "query2"],
+ ),
+ ):
+ return data
+
+ with pytest.warns(DeprecationWarning):
+
+ @app.get("/query_example_examples/")
+ def query_example_examples(
+ data: Union[str, None] = Query(
+ default=None,
+ example="query_overridden",
+ examples=["query1", "query2"],
+ ),
+ ):
+ return data
+
+ with pytest.warns(DeprecationWarning):
+
+ @app.get("/header_example/")
+ def header_example(
+ data: Union[str, None] = Header(
+ default=None,
+ example="header1",
+ ),
+ ):
+ return data
+
+ @app.get("/header_examples/")
+ def header_examples(
+ data: Union[str, None] = Header(
+ default=None,
+ examples=[
+ "header1",
+ "header2",
+ ],
+ ),
+ ):
+ return data
+
+ with pytest.warns(DeprecationWarning):
+
+ @app.get("/header_example_examples/")
+ def header_example_examples(
+ data: Union[str, None] = Header(
+ default=None,
+ example="header_overridden",
+ examples=["header1", "header2"],
+ ),
+ ):
+ return data
+
+ with pytest.warns(DeprecationWarning):
+
+ @app.get("/cookie_example/")
+ def cookie_example(
+ data: Union[str, None] = Cookie(
+ default=None,
+ example="cookie1",
+ ),
+ ):
+ return data
+
+ @app.get("/cookie_examples/")
+ def cookie_examples(
+ data: Union[str, None] = Cookie(
+ default=None,
+ examples=["cookie1", "cookie2"],
+ ),
+ ):
+ return data
+
+ with pytest.warns(DeprecationWarning):
+
+ @app.get("/cookie_example_examples/")
+ def cookie_example_examples(
+ data: Union[str, None] = Cookie(
+ default=None,
+ example="cookie_overridden",
+ examples=["cookie1", "cookie2"],
+ ),
+ ):
+ return data
+
+ return app
def test_call_api():
+ app = create_app()
+ client = TestClient(app)
response = client.post("/schema_extra/", json={"data": "Foo"})
assert response.status_code == 200, response.text
response = client.post("/example/", json={"data": "Foo"})
* Body(example={}) overrides schema_extra in pydantic model
* Body(examples{}) overrides Body(example={}) and schema_extra in pydantic model
"""
+ app = create_app()
+ client = TestClient(app)
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/schema_extra/": {
"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"
- }
- },
- },
+ "schema": {
+ "allOf": [{"$ref": "#/components/schemas/Item"}],
+ "title": "Item",
+ "examples": [
+ {"data": "Data in Body examples, example1"},
+ {"data": "Data in Body examples, example2"},
+ ],
+ }
}
},
"required": True,
"requestBody": {
"content": {
"application/json": {
- "schema": {"$ref": "#/components/schemas/Item"},
- "examples": {
- "example1": {
- "value": {"data": "examples example_examples 1"}
- },
- "example2": {
- "value": {"data": "examples example_examples 2"}
- },
+ "schema": {
+ "allOf": [{"$ref": "#/components/schemas/Item"}],
+ "title": "Item",
+ "examples": [
+ {"data": "examples example_examples 1"},
+ {"data": "examples example_examples 2"},
+ ],
},
+ "example": {"data": "Overridden example"},
}
},
"required": True,
"parameters": [
{
"required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "examples": {
- "example1": {
- "summary": "item ID summary",
- "value": "item_1",
- },
- "example2": {"value": "item_2"},
+ "schema": {
+ "title": "Item Id",
+ "type": "string",
+ "examples": ["item_1", "item_2"],
},
"name": "item_id",
"in": "path",
"parameters": [
{
"required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "examples": {
- "example1": {
- "summary": "item ID summary",
- "value": "item_1",
- },
- "example2": {"value": "item_2"},
+ "schema": {
+ "title": "Item Id",
+ "type": "string",
+ "examples": ["item_1", "item_2"],
},
+ "example": "item_overridden",
"name": "item_id",
"in": "path",
}
"parameters": [
{
"required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "Query example 1",
- "value": "query1",
- },
- "example2": {"value": "query2"},
+ "schema": {
+ "type": "string",
+ "title": "Data",
+ "examples": ["query1", "query2"],
},
"name": "data",
"in": "query",
"parameters": [
{
"required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "Query example 1",
- "value": "query1",
- },
- "example2": {"value": "query2"},
+ "schema": {
+ "type": "string",
+ "title": "Data",
+ "examples": ["query1", "query2"],
},
+ "example": "query_overridden",
"name": "data",
"in": "query",
}
"parameters": [
{
"required": False,
- "schema": {"title": "Data", "type": "string"},
+ "schema": {"type": "string", "title": "Data"},
"example": "header1",
"name": "data",
"in": "header",
"parameters": [
{
"required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "header example 1",
- "value": "header1",
- },
- "example2": {"value": "header2"},
+ "schema": {
+ "type": "string",
+ "title": "Data",
+ "examples": ["header1", "header2"],
},
"name": "data",
"in": "header",
"parameters": [
{
"required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "Query example 1",
- "value": "header1",
- },
- "example2": {"value": "header2"},
+ "schema": {
+ "type": "string",
+ "title": "Data",
+ "examples": ["header1", "header2"],
},
+ "example": "header_overridden",
"name": "data",
"in": "header",
}
"parameters": [
{
"required": False,
- "schema": {"title": "Data", "type": "string"},
+ "schema": {"type": "string", "title": "Data"},
"example": "cookie1",
"name": "data",
"in": "cookie",
"parameters": [
{
"required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "cookie example 1",
- "value": "cookie1",
- },
- "example2": {"value": "cookie2"},
+ "schema": {
+ "type": "string",
+ "title": "Data",
+ "examples": ["cookie1", "cookie2"],
},
"name": "data",
"in": "cookie",
"parameters": [
{
"required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "Query example 1",
- "value": "cookie1",
- },
- "example2": {"value": "cookie2"},
+ "schema": {
+ "type": "string",
+ "title": "Data",
+ "examples": ["cookie1", "cookie2"],
},
+ "example": "cookie_overridden",
"name": "data",
"in": "cookie",
}
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/login": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/login": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/login": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/http-no-body-statuscode-exception": {
with client:
response = client.get("/openapi.json")
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/invoices/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/model-with-tuple/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/notes/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/app": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/app": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"servers": [
{"url": "/api/v1"},
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"servers": [
{"url": "https://stag.example.com", "description": "Staging environment"},
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/index-weights/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/index-weights/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
assert response.status_code == 200, response.text
response = client.get("/openapi.json")
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/typer": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/fastapi": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/pydantic": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
assert response.status_code == 200
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/next": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/authors/{author_id}/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/predict": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {
"title": "Custom title",
+ "summary": "This is a very custom OpenAPI schema",
+ "description": "Here's a longer description of the custom **OpenAPI** schema",
"version": "2.5.0",
- "description": "This is a very custom OpenAPI schema",
"x-logo": {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
},
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/keyword-weights/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/keyword-weights/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items-header/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/unicorns/{name}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
assert response.status_code == 200
# insert_assert(response.json())
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
assert response.status_code == 200
# insert_assert(response.json())
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
assert response.status_code == 200
# insert_assert(response.json())
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
assert response.status_code == 200
# insert_assert(response.json())
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
assert response.status_code == 200
# insert_assert(response.json())
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {
"title": "ChimichangApp",
+ "summary": "Deadpool's favorite app. Nuff said.",
"description": "\nChimichangApp API helps you do awesome stuff. 🚀\n\n## Items\n\nYou can **read items**.\n\n## Users\n\nYou will be able to:\n\n* **Create users** (_not implemented_).\n* **Read users** (_not implemented_).\n",
"termsOfService": "http://example.com/terms/",
"contact": {
--- /dev/null
+from fastapi.testclient import TestClient
+
+from docs_src.metadata.tutorial001_1 import app
+
+client = TestClient(app)
+
+
+def test_items():
+ response = client.get("/items/")
+ assert response.status_code == 200, response.text
+ assert response.json() == [{"name": "Katana"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {
+ "title": "ChimichangApp",
+ "summary": "Deadpool's favorite app. Nuff said.",
+ "description": "\nChimichangApp API helps you do awesome stuff. 🚀\n\n## Items\n\nYou can **read items**.\n\n## Users\n\nYou will be able to:\n\n* **Create users** (_not implemented_).\n* **Read users** (_not implemented_).\n",
+ "termsOfService": "http://example.com/terms/",
+ "contact": {
+ "name": "Deadpoolio the Amazing",
+ "url": "http://x-force.example.com/contact/",
+ "email": "dp@x-force.example.com",
+ },
+ "license": {
+ "name": "Apache 2.0",
+ "identifier": "MIT",
+ },
+ "version": "0.0.1",
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ }
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/invoices/": {
--- /dev/null
+from fastapi.testclient import TestClient
+
+from docs_src.openapi_webhooks.tutorial001 import app
+
+client = TestClient(app)
+
+
+def test_get():
+ response = client.get("/users/")
+ assert response.status_code == 200, response.text
+ assert response.json() == ["Rick", "Morty"]
+
+
+def test_dummy_webhook():
+ # Just for coverage
+ app.webhooks.routes[0].endpoint({})
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/": {
+ "get": {
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ "webhooks": {
+ "new-subscription": {
+ "post": {
+ "summary": "New Subscription",
+ "description": "When a new user subscribes to your service we'll send you a POST request with this\ndata to the URL that you register for the event `new-subscription` in the dashboard.",
+ "operationId": "new_subscriptionnew_subscription_post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Subscription"}
+ }
+ },
+ "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": {
+ "properties": {
+ "detail": {
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ "type": "array",
+ "title": "Detail",
+ }
+ },
+ "type": "object",
+ "title": "HTTPValidationError",
+ },
+ "Subscription": {
+ "properties": {
+ "username": {"type": "string", "title": "Username"},
+ "montly_fee": {"type": "number", "title": "Montly Fee"},
+ "start_date": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Start Date",
+ },
+ },
+ "type": "object",
+ "required": ["username", "montly_fee", "start_date"],
+ "title": "Subscription",
+ },
+ "ValidationError": {
+ "properties": {
+ "loc": {
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ "type": "array",
+ "title": "Location",
+ },
+ "msg": {"type": "string", "title": "Message"},
+ "type": {"type": "string", "title": "Error Type"},
+ },
+ "type": "object",
+ "required": ["loc", "msg", "type"],
+ "title": "ValidationError",
+ },
+ }
+ },
+ }
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {},
}
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/{file_path}": {
assert response.status_code == 200, response.text
data = response.json()
assert data == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/models/{model_name}": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/login/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/login/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/login/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/files/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/user/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/user/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/user/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/portal": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/teleport": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/portal": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/portal": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/user/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}/name": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}/name": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}/name": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}/name": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"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,
+ "schema": {
+ "allOf": [{"$ref": "#/components/schemas/Item"}],
+ "title": "Item",
+ "examples": [
+ {
+ "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",
+ {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {"name": "Bar", "price": "35.4"},
},
- },
- },
+ {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ ],
+ }
}
},
"required": True,
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"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,
+ "schema": {
+ "allOf": [{"$ref": "#/components/schemas/Item"}],
+ "title": "Item",
+ "examples": [
+ {
+ "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",
+ {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {"name": "Bar", "price": "35.4"},
},
- },
- },
+ {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ ],
+ }
}
},
"required": True,
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"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,
+ "schema": {
+ "allOf": [{"$ref": "#/components/schemas/Item"}],
+ "title": "Item",
+ "examples": [
+ {
+ "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",
+ {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {"name": "Bar", "price": "35.4"},
},
- },
- },
+ {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ ],
+ }
}
},
"required": True,
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"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,
+ "schema": {
+ "allOf": [{"$ref": "#/components/schemas/Item"}],
+ "title": "Item",
+ "examples": [
+ {
+ "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",
+ {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {"name": "Bar", "price": "35.4"},
},
- },
- },
+ {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ ],
+ }
}
},
"required": True,
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"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,
+ "schema": {
+ "allOf": [{"$ref": "#/components/schemas/Item"}],
+ "title": "Item",
+ "examples": [
+ {
+ "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",
+ {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {"name": "Bar", "price": "35.4"},
},
- },
- },
+ {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ ],
+ }
}
},
"required": True,
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/": {
client = TestClient(app)
openapi_schema_main = {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/app": {
},
}
openapi_schema_sub = {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/sub": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
--- /dev/null
+from datetime import datetime
+
+from fastapi import FastAPI, Security
+from fastapi.security import HTTPBearer
+from fastapi.testclient import TestClient
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+bearer_scheme = HTTPBearer()
+
+
+class Subscription(BaseModel):
+ username: str
+ montly_fee: float
+ start_date: datetime
+
+
+@app.webhooks.post("new-subscription")
+def new_subscription(
+ body: Subscription, token: Annotated[str, Security(bearer_scheme)]
+):
+ """
+ When a new user subscribes to your service we'll send you a POST request with this
+ data to the URL that you register for the event `new-subscription` in the dashboard.
+ """
+
+
+client = TestClient(app)
+
+
+def test_dummy_webhook():
+ # Just for coverage
+ new_subscription(body={}, token="Bearer 123")
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ # insert_assert(response.json())
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {},
+ "webhooks": {
+ "new-subscription": {
+ "post": {
+ "summary": "New Subscription",
+ "description": "When a new user subscribes to your service we'll send you a POST request with this\ndata to the URL that you register for the event `new-subscription` in the dashboard.",
+ "operationId": "new_subscriptionnew_subscription_post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Subscription"}
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "security": [{"HTTPBearer": []}],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "properties": {
+ "detail": {
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ "type": "array",
+ "title": "Detail",
+ }
+ },
+ "type": "object",
+ "title": "HTTPValidationError",
+ },
+ "Subscription": {
+ "properties": {
+ "username": {"type": "string", "title": "Username"},
+ "montly_fee": {"type": "number", "title": "Montly Fee"},
+ "start_date": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Start Date",
+ },
+ },
+ "type": "object",
+ "required": ["username", "montly_fee", "start_date"],
+ "title": "Subscription",
+ },
+ "ValidationError": {
+ "properties": {
+ "loc": {
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ "type": "array",
+ "title": "Location",
+ },
+ "msg": {"type": "string", "title": "Message"},
+ "type": {"type": "string", "title": "Error Type"},
+ },
+ "type": "object",
+ "required": ["loc", "msg", "type"],
+ "title": "ValidationError",
+ },
+ },
+ "securitySchemes": {"HTTPBearer": {"type": "http", "scheme": "bearer"}},
+ },
+ }