This commit is contained in:
Motov Yurii 2025-12-12 08:31:06 +00:00 committed by GitHub
commit c408fb1ecf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
610 changed files with 482 additions and 5164 deletions

View File

@ -26,7 +26,7 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod
For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write: For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write:
{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *} {* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
/// note /// note
@ -203,7 +203,7 @@ For example, you can declare a response with a status code `404` that uses a Pyd
And a response with a status code `200` that uses your `response_model`, but includes a custom `example`: And a response with a status code `200` that uses your `response_model`, but includes a custom `example`:
{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *} {* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
It will all be combined and included in your OpenAPI, and shown in the API docs: It will all be combined and included in your OpenAPI, and shown in the API docs:

View File

@ -32,11 +32,11 @@ For a simple example, let's consider a file structure similar to the one describ
The file `main.py` would have: The file `main.py` would have:
{* ../../docs_src/async_tests/main.py *} {* ../../docs_src/async_tests/app_a_py39/main.py *}
The file `test_main.py` would have the tests for `main.py`, it could look like this now: The file `test_main.py` would have the tests for `main.py`, it could look like this now:
{* ../../docs_src/async_tests/test_main.py *} {* ../../docs_src/async_tests/app_a_py39/test_main.py *}
## Run it { #run-it } ## Run it { #run-it }
@ -56,7 +56,7 @@ $ pytest
The marker `@pytest.mark.anyio` tells pytest that this test function should be called asynchronously: The marker `@pytest.mark.anyio` tells pytest that this test function should be called asynchronously:
{* ../../docs_src/async_tests/test_main.py hl[7] *} {* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
/// tip /// tip
@ -66,7 +66,7 @@ Note that the test function is now `async def` instead of just `def` as before w
Then we can create an `AsyncClient` with the app, and send async requests to it, using `await`. Then we can create an `AsyncClient` with the app, and send async requests to it, using `await`.
{* ../../docs_src/async_tests/test_main.py hl[9:12] *} {* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
This is the equivalent to: This is the equivalent to:

View File

@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*"
For example, let's say you define a *path operation* `/items/`: For example, let's say you define a *path operation* `/items/`:
{* ../../docs_src/behind_a_proxy/tutorial001_01.py hl[6] *} {* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *}
If the client tries to go to `/items`, by default, it would be redirected to `/items/`. If the client tries to go to `/items`, by default, it would be redirected to `/items/`.
@ -115,7 +115,7 @@ In this case, the original path `/app` would actually be served at `/api/v1/app`
Even though all your code is written assuming there's just `/app`. Even though all your code is written assuming there's just `/app`.
{* ../../docs_src/behind_a_proxy/tutorial001.py hl[6] *} {* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *}
And the proxy would be **"stripping"** the **path prefix** on the fly before transmitting the request to the app server (probably Uvicorn via FastAPI CLI), keeping your application convinced that it is being served at `/app`, so that you don't have to update all your code to include the prefix `/api/v1`. And the proxy would be **"stripping"** the **path prefix** on the fly before transmitting the request to the app server (probably Uvicorn via FastAPI CLI), keeping your application convinced that it is being served at `/app`, so that you don't have to update all your code to include the prefix `/api/v1`.
@ -193,7 +193,7 @@ You can get the current `root_path` used by your application for each request, i
Here we are including it in the message just for demonstration purposes. Here we are including it in the message just for demonstration purposes.
{* ../../docs_src/behind_a_proxy/tutorial001.py hl[8] *} {* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *}
Then, if you start Uvicorn with: Then, if you start Uvicorn with:
@ -220,7 +220,7 @@ The response would be something like:
Alternatively, if you don't have a way to provide a command line option like `--root-path` or equivalent, you can set the `root_path` parameter when creating your FastAPI app: Alternatively, if you don't have a way to provide a command line option like `--root-path` or equivalent, you can set the `root_path` parameter when creating your FastAPI app:
{* ../../docs_src/behind_a_proxy/tutorial002.py hl[3] *} {* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *}
Passing the `root_path` to `FastAPI` would be the equivalent of passing the `--root-path` command line option to Uvicorn or Hypercorn. Passing the `root_path` to `FastAPI` would be the equivalent of passing the `--root-path` command line option to Uvicorn or Hypercorn.
@ -400,7 +400,7 @@ If you pass a custom list of `servers` and there's a `root_path` (because your A
For example: For example:
{* ../../docs_src/behind_a_proxy/tutorial003.py hl[4:7] *} {* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *}
Will generate an OpenAPI schema like: Will generate an OpenAPI schema like:
@ -455,7 +455,7 @@ If you don't specify the `servers` parameter and `root_path` is equal to `/`, th
If you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`: If you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`:
{* ../../docs_src/behind_a_proxy/tutorial004.py hl[9] *} {* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *}
and then it won't include it in the OpenAPI schema. and then it won't include it in the OpenAPI schema.

View File

@ -30,7 +30,7 @@ This is because by default, FastAPI will inspect every item inside and make sure
But if you are certain that the content that you are returning is **serializable with JSON**, you can pass it directly to the response class and avoid the extra overhead that FastAPI would have by passing your return content through the `jsonable_encoder` before passing it to the response class. But if you are certain that the content that you are returning is **serializable with JSON**, you can pass it directly to the response class and avoid the extra overhead that FastAPI would have by passing your return content through the `jsonable_encoder` before passing it to the response class.
{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *} {* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
/// info /// info
@ -55,7 +55,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
* Import `HTMLResponse`. * Import `HTMLResponse`.
* Pass `HTMLResponse` as the parameter `response_class` of your *path operation decorator*. * Pass `HTMLResponse` as the parameter `response_class` of your *path operation decorator*.
{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *} {* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
/// info /// info
@ -73,7 +73,7 @@ As seen in [Return a Response directly](response-directly.md){.internal-link tar
The same example from above, returning an `HTMLResponse`, could look like: The same example from above, returning an `HTMLResponse`, could look like:
{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *} {* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
/// warning /// warning
@ -97,7 +97,7 @@ The `response_class` will then be used only to document the OpenAPI *path operat
For example, it could be something like: For example, it could be something like:
{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *} {* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
In this example, the function `generate_html_response()` already generates and returns a `Response` instead of returning the HTML in a `str`. In this example, the function `generate_html_response()` already generates and returns a `Response` instead of returning the HTML in a `str`.
@ -136,7 +136,7 @@ It accepts the following parameters:
FastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the `media_type` and appending a charset for text types. FastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the `media_type` and appending a charset for text types.
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *} {* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
### `HTMLResponse` { #htmlresponse } ### `HTMLResponse` { #htmlresponse }
@ -146,7 +146,7 @@ Takes some text or bytes and returns an HTML response, as you read above.
Takes some text or bytes and returns a plain text response. Takes some text or bytes and returns a plain text response.
{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *} {* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
### `JSONResponse` { #jsonresponse } ### `JSONResponse` { #jsonresponse }
@ -180,7 +180,7 @@ This requires installing `ujson` for example with `pip install ujson`.
/// ///
{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *} {* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
/// tip /// tip
@ -194,14 +194,14 @@ Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default
You can return a `RedirectResponse` directly: You can return a `RedirectResponse` directly:
{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *} {* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
--- ---
Or you can use it in the `response_class` parameter: Or you can use it in the `response_class` parameter:
{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *} {* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
If you do that, then you can return the URL directly from your *path operation* function. If you do that, then you can return the URL directly from your *path operation* function.
@ -211,13 +211,13 @@ In this case, the `status_code` used will be the default one for the `RedirectRe
You can also use the `status_code` parameter combined with the `response_class` parameter: You can also use the `status_code` parameter combined with the `response_class` parameter:
{* ../../docs_src/custom_response/tutorial006c.py hl[2,7,9] *} {* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
### `StreamingResponse` { #streamingresponse } ### `StreamingResponse` { #streamingresponse }
Takes an async generator or a normal generator/iterator and streams the response body. Takes an async generator or a normal generator/iterator and streams the response body.
{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *} {* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
#### Using `StreamingResponse` with file-like objects { #using-streamingresponse-with-file-like-objects } #### Using `StreamingResponse` with file-like objects { #using-streamingresponse-with-file-like-objects }
@ -227,7 +227,7 @@ That way, you don't have to read it all first in memory, and you can pass that g
This includes many libraries to interact with cloud storage, video processing, and others. This includes many libraries to interact with cloud storage, video processing, and others.
{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *} {* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
1. This is the generator function. It's a "generator function" because it contains `yield` statements inside. 1. This is the generator function. It's a "generator function" because it contains `yield` statements inside.
2. By using a `with` block, we make sure that the file-like object is closed after the generator function is done. So, after it finishes sending the response. 2. By using a `with` block, we make sure that the file-like object is closed after the generator function is done. So, after it finishes sending the response.
@ -256,11 +256,11 @@ Takes a different set of arguments to instantiate than the other response types:
File responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers. File responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers.
{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *} {* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
You can also use the `response_class` parameter: You can also use the `response_class` parameter:
{* ../../docs_src/custom_response/tutorial009b.py hl[2,8,10] *} {* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
In this case, you can return the file path directly from your *path operation* function. In this case, you can return the file path directly from your *path operation* function.
@ -274,7 +274,7 @@ Let's say you want it to return indented and formatted JSON, so you want to use
You could create a `CustomORJSONResponse`. The main thing you have to do is create a `Response.render(content)` method that returns the content as `bytes`: You could create a `CustomORJSONResponse`. The main thing you have to do is create a `Response.render(content)` method that returns the content as `bytes`:
{* ../../docs_src/custom_response/tutorial009c.py hl[9:14,17] *} {* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
Now instead of returning: Now instead of returning:
@ -300,7 +300,7 @@ The parameter that defines this is `default_response_class`.
In the example below, **FastAPI** will use `ORJSONResponse` by default, in all *path operations*, instead of `JSONResponse`. In the example below, **FastAPI** will use `ORJSONResponse` by default, in all *path operations*, instead of `JSONResponse`.
{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *} {* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
/// tip /// tip

View File

@ -30,7 +30,7 @@ Let's start with an example and then see it in detail.
We create an async function `lifespan()` with `yield` like this: We create an async function `lifespan()` with `yield` like this:
{* ../../docs_src/events/tutorial003.py hl[16,19] *} {* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
Here we are simulating the expensive *startup* operation of loading the model by putting the (fake) model function in the dictionary with machine learning models before the `yield`. This code will be executed **before** the application **starts taking requests**, during the *startup*. Here we are simulating the expensive *startup* operation of loading the model by putting the (fake) model function in the dictionary with machine learning models before the `yield`. This code will be executed **before** the application **starts taking requests**, during the *startup*.
@ -48,7 +48,7 @@ Maybe you need to start a new version, or you just got tired of running it. 🤷
The first thing to notice, is that we are defining an async function with `yield`. This is very similar to Dependencies with `yield`. The first thing to notice, is that we are defining an async function with `yield`. This is very similar to Dependencies with `yield`.
{* ../../docs_src/events/tutorial003.py hl[14:19] *} {* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
The first part of the function, before the `yield`, will be executed **before** the application starts. The first part of the function, before the `yield`, will be executed **before** the application starts.
@ -60,7 +60,7 @@ If you check, the function is decorated with an `@asynccontextmanager`.
That converts the function into something called an "**async context manager**". That converts the function into something called an "**async context manager**".
{* ../../docs_src/events/tutorial003.py hl[1,13] *} {* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
A **context manager** in Python is something that you can use in a `with` statement, for example, `open()` can be used as a context manager: A **context manager** in Python is something that you can use in a `with` statement, for example, `open()` can be used as a context manager:
@ -82,7 +82,7 @@ In our code example above, we don't use it directly, but we pass it to FastAPI f
The `lifespan` parameter of the `FastAPI` app takes an **async context manager**, so we can pass our new `lifespan` async context manager to it. The `lifespan` parameter of the `FastAPI` app takes an **async context manager**, so we can pass our new `lifespan` async context manager to it.
{* ../../docs_src/events/tutorial003.py hl[22] *} {* ../../docs_src/events/tutorial003_py39.py hl[22] *}
## Alternative Events (deprecated) { #alternative-events-deprecated } ## Alternative Events (deprecated) { #alternative-events-deprecated }
@ -104,7 +104,7 @@ These functions can be declared with `async def` or normal `def`.
To add a function that should be run before the application starts, declare it with the event `"startup"`: To add a function that should be run before the application starts, declare it with the event `"startup"`:
{* ../../docs_src/events/tutorial001.py hl[8] *} {* ../../docs_src/events/tutorial001_py39.py hl[8] *}
In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values. In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values.
@ -116,7 +116,7 @@ And your application won't start receiving requests until all the `startup` even
To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`: To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`:
{* ../../docs_src/events/tutorial002.py hl[6] *} {* ../../docs_src/events/tutorial002_py39.py hl[6] *}
Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`. Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`.

View File

@ -167,7 +167,7 @@ But for the generated client, we could **modify** the OpenAPI operation IDs righ
We could download the OpenAPI JSON to a file `openapi.json` and then we could **remove that prefixed tag** with a script like this: We could download the OpenAPI JSON to a file `openapi.json` and then we could **remove that prefixed tag** with a script like this:
{* ../../docs_src/generate_clients/tutorial004.py *} {* ../../docs_src/generate_clients/tutorial004_py39.py *}
//// tab | Node.js //// tab | Node.js

View File

@ -57,13 +57,13 @@ Enforces that all incoming requests must either be `https` or `wss`.
Any incoming request to `http` or `ws` will be redirected to the secure scheme instead. Any incoming request to `http` or `ws` will be redirected to the secure scheme instead.
{* ../../docs_src/advanced_middleware/tutorial001.py hl[2,6] *} {* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *}
## `TrustedHostMiddleware` { #trustedhostmiddleware } ## `TrustedHostMiddleware` { #trustedhostmiddleware }
Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks. Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks.
{* ../../docs_src/advanced_middleware/tutorial002.py hl[2,6:8] *} {* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *}
The following arguments are supported: The following arguments are supported:
@ -78,7 +78,7 @@ Handles GZip responses for any request that includes `"gzip"` in the `Accept-Enc
The middleware will handle both standard and streaming responses. The middleware will handle both standard and streaming responses.
{* ../../docs_src/advanced_middleware/tutorial003.py hl[2,6] *} {* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *}
The following arguments are supported: The following arguments are supported:

View File

@ -32,7 +32,7 @@ Webhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0`
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()`. 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()`.
{* ../../docs_src/openapi_webhooks/tutorial001.py hl[9:13,36:53] *} {* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *}
The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**. The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**.

View File

@ -12,7 +12,7 @@ You can set the OpenAPI `operationId` to be used in your *path operation* with t
You would have to make sure that it is unique for each operation. You would have to make sure that it is unique for each operation.
{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *} {* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
### Using the *path operation function* name as the operationId { #using-the-path-operation-function-name-as-the-operationid } ### Using the *path operation function* name as the operationId { #using-the-path-operation-function-name-as-the-operationid }
@ -20,7 +20,7 @@ If you want to use your APIs' function names as `operationId`s, you can iterate
You should do it after adding all your *path operations*. You should do it after adding all your *path operations*.
{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2, 12:21, 24] *} {* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
/// tip /// tip
@ -40,7 +40,7 @@ Even if they are in different modules (Python files).
To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`: To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`:
{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *} {* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
## Advanced description from docstring { #advanced-description-from-docstring } ## Advanced description from docstring { #advanced-description-from-docstring }
@ -92,7 +92,7 @@ You can extend the OpenAPI schema for a *path operation* using the parameter `op
This `openapi_extra` can be helpful, for example, to declare [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions): This `openapi_extra` can be helpful, for example, to declare [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
{* ../../docs_src/path_operation_advanced_configuration/tutorial005.py hl[6] *} {* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
If you open the automatic API docs, your extension will show up at the bottom of the specific *path operation*. If you open the automatic API docs, your extension will show up at the bottom of the specific *path operation*.
@ -139,7 +139,7 @@ For example, you could decide to read and validate the request with your own cod
You could do that with `openapi_extra`: You could do that with `openapi_extra`:
{* ../../docs_src/path_operation_advanced_configuration/tutorial006.py hl[19:36, 39:40] *} {* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
In this example, we didn't declare any Pydantic model. In fact, the request body is not even <abbr title="converted from some plain format, like bytes, into Python objects">parsed</abbr> as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way. In this example, we didn't declare any Pydantic model. In fact, the request body is not even <abbr title="converted from some plain format, like bytes, into Python objects">parsed</abbr> as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way.

View File

@ -20,7 +20,7 @@ You can declare a parameter of type `Response` in your *path operation function*
And then you can set the `status_code` in that *temporal* response object. And then you can set the `status_code` in that *temporal* response object.
{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *} {* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *}
And then you can return any object you need, as you normally would (a `dict`, a database model, etc). And then you can return any object you need, as you normally would (a `dict`, a database model, etc).

View File

@ -6,7 +6,7 @@ You can declare a parameter of type `Response` in your *path operation function*
And then you can set cookies in that *temporal* response object. And then you can set cookies in that *temporal* response object.
{* ../../docs_src/response_cookies/tutorial002.py hl[1, 8:9] *} {* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *}
And then you can return any object you need, as you normally would (a `dict`, a database model, etc). And then you can return any object you need, as you normally would (a `dict`, a database model, etc).
@ -24,7 +24,7 @@ To do that, you can create a response as described in [Return a Response Directl
Then set Cookies in it, and then return it: Then set Cookies in it, and then return it:
{* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *} {* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *}
/// tip /// tip

View File

@ -54,7 +54,7 @@ Let's say that you want to return an <a href="https://en.wikipedia.org/wiki/XML"
You could put your XML content in a string, put that in a `Response`, and return it: You could put your XML content in a string, put that in a `Response`, and return it:
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *} {* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
## Notes { #notes } ## Notes { #notes }

View File

@ -6,7 +6,7 @@ You can declare a parameter of type `Response` in your *path operation function*
And then you can set headers in that *temporal* response object. And then you can set headers in that *temporal* response object.
{* ../../docs_src/response_headers/tutorial002.py hl[1, 7:8] *} {* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *}
And then you can return any object you need, as you normally would (a `dict`, a database model, etc). And then you can return any object you need, as you normally would (a `dict`, a database model, etc).
@ -22,7 +22,7 @@ You can also add headers when you return a `Response` directly.
Create a response as described in [Return a Response Directly](response-directly.md){.internal-link target=_blank} and pass the headers as an additional parameter: Create a response as described in [Return a Response Directly](response-directly.md){.internal-link target=_blank} and pass the headers as an additional parameter:
{* ../../docs_src/response_headers/tutorial001.py hl[10:12] *} {* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *}
/// note | Technical Details /// note | Technical Details

View File

@ -62,7 +62,7 @@ You can use all the same validation features and tools you use for Pydantic mode
//// tab | Pydantic v2 //// tab | Pydantic v2
{* ../../docs_src/settings/tutorial001.py hl[2,5:8,11] *} {* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
//// ////
@ -74,7 +74,7 @@ In Pydantic v1 you would import `BaseSettings` directly from `pydantic` instead
/// ///
{* ../../docs_src/settings/tutorial001_pv1.py hl[2,5:8,11] *} {* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
//// ////
@ -92,7 +92,7 @@ Next it will convert and validate the data. So, when you use that `settings` obj
Then you can use the new `settings` object in your application: Then you can use the new `settings` object in your application:
{* ../../docs_src/settings/tutorial001.py hl[18:20] *} {* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *}
### Run the server { #run-the-server } ### Run the server { #run-the-server }
@ -126,11 +126,11 @@ You could put those settings in another module file as you saw in [Bigger Applic
For example, you could have a file `config.py` with: For example, you could have a file `config.py` with:
{* ../../docs_src/settings/app01/config.py *} {* ../../docs_src/settings/app01_py39/config.py *}
And then use it in a file `main.py`: And then use it in a file `main.py`:
{* ../../docs_src/settings/app01/main.py hl[3,11:13] *} {* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *}
/// tip /// tip

View File

@ -10,7 +10,7 @@ If you need to have two independent FastAPI applications, with their own indepen
First, create the main, top-level, **FastAPI** application, and its *path operations*: First, create the main, top-level, **FastAPI** application, and its *path operations*:
{* ../../docs_src/sub_applications/tutorial001.py hl[3, 6:8] *} {* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *}
### Sub-application { #sub-application } ### Sub-application { #sub-application }
@ -18,7 +18,7 @@ Then, create your sub-application, and its *path operations*.
This sub-application is just another standard FastAPI application, but this is the one that will be "mounted": This sub-application is just another standard FastAPI application, but this is the one that will be "mounted":
{* ../../docs_src/sub_applications/tutorial001.py hl[11, 14:16] *} {* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *}
### Mount the sub-application { #mount-the-sub-application } ### Mount the sub-application { #mount-the-sub-application }
@ -26,7 +26,7 @@ In your top-level application, `app`, mount the sub-application, `subapi`.
In this case, it will be mounted at the path `/subapi`: In this case, it will be mounted at the path `/subapi`:
{* ../../docs_src/sub_applications/tutorial001.py hl[11, 19] *} {* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *}
### Check the automatic API docs { #check-the-automatic-api-docs } ### Check the automatic API docs { #check-the-automatic-api-docs }

View File

@ -27,7 +27,7 @@ $ pip install jinja2
* Declare a `Request` parameter in the *path operation* that will return a template. * Declare a `Request` parameter in the *path operation* that will return a template.
* Use the `templates` you created to render and return a `TemplateResponse`, pass the name of the template, the request object, and a "context" dictionary with key-value pairs to be used inside of the Jinja2 template. * Use the `templates` you created to render and return a `TemplateResponse`, pass the name of the template, the request object, and a "context" dictionary with key-value pairs to be used inside of the Jinja2 template.
{* ../../docs_src/templates/tutorial001.py hl[4,11,15:18] *} {* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *}
/// note /// note

View File

@ -2,11 +2,11 @@
When you need `lifespan` to run in your tests, you can use the `TestClient` with a `with` statement: When you need `lifespan` to run in your tests, you can use the `TestClient` with a `with` statement:
{* ../../docs_src/app_testing/tutorial004.py hl[9:15,18,27:28,30:32,41:43] *} {* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *}
You can read more details about the ["Running lifespan in tests in the official Starlette documentation site."](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) You can read more details about the ["Running lifespan in tests in the official Starlette documentation site."](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)
For the deprecated `startup` and `shutdown` events, you can use the `TestClient` as follows: For the deprecated `startup` and `shutdown` events, you can use the `TestClient` as follows:
{* ../../docs_src/app_testing/tutorial003.py hl[9:12,20:24] *} {* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *}

View File

@ -4,7 +4,7 @@ You can use the same `TestClient` to test WebSockets.
For this, you use the `TestClient` in a `with` statement, connecting to the WebSocket: For this, you use the `TestClient` in a `with` statement, connecting to the WebSocket:
{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *} {* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *}
/// note /// note

View File

@ -29,7 +29,7 @@ Let's imagine you want to get the client's IP address/host inside of your *path
For that you need to access the request directly. For that you need to access the request directly.
{* ../../docs_src/using_request_directly/tutorial001.py hl[1,7:8] *} {* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *}
By declaring a *path operation function* parameter with the type being the `Request` **FastAPI** will know to pass the `Request` in that parameter. By declaring a *path operation function* parameter with the type being the `Request` **FastAPI** will know to pass the `Request` in that parameter.

View File

@ -38,13 +38,13 @@ In production you would have one of the options above.
But it's the simplest way to focus on the server-side of WebSockets and have a working example: But it's the simplest way to focus on the server-side of WebSockets and have a working example:
{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *} {* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *}
## Create a `websocket` { #create-a-websocket } ## Create a `websocket` { #create-a-websocket }
In your **FastAPI** application, create a `websocket`: In your **FastAPI** application, create a `websocket`:
{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *} {* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *}
/// note | Technical Details /// note | Technical Details
@ -58,7 +58,7 @@ You could also use `from starlette.websockets import WebSocket`.
In your WebSocket route you can `await` for messages and send messages. In your WebSocket route you can `await` for messages and send messages.
{* ../../docs_src/websockets/tutorial001.py hl[48:52] *} {* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *}
You can receive and send binary, text, and JSON data. You can receive and send binary, text, and JSON data.

View File

@ -12,7 +12,7 @@ Then wrap the WSGI (e.g. Flask) app with the middleware.
And then mount that under a path. And then mount that under a path.
{* ../../docs_src/wsgi/tutorial001.py hl[2:3,3] *} {* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
## Check it { #check-it } ## Check it { #check-it }

View File

@ -29,7 +29,7 @@ You can easily use the same Pydantic settings to configure your generated OpenAP
For example: For example:
{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *} {* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *}
Here we declare the setting `openapi_url` with the same default of `"/openapi.json"`. Here we declare the setting `openapi_url` with the same default of `"/openapi.json"`.

View File

@ -18,7 +18,7 @@ Without changing the settings, syntax highlighting is enabled by default:
But you can disable it by setting `syntaxHighlight` to `False`: But you can disable it by setting `syntaxHighlight` to `False`:
{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *} {* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *}
...and then Swagger UI won't show the syntax highlighting anymore: ...and then Swagger UI won't show the syntax highlighting anymore:
@ -28,7 +28,7 @@ But you can disable it by setting `syntaxHighlight` to `False`:
The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle): The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle):
{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *} {* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *}
That configuration would change the syntax highlighting color theme: That configuration would change the syntax highlighting color theme:
@ -46,7 +46,7 @@ You can override any of them by setting a different value in the argument `swagg
For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`: For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`:
{* ../../docs_src/configure_swagger_ui/tutorial003.py hl[3] *} {* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *}
## Other Swagger UI Parameters { #other-swagger-ui-parameters } ## Other Swagger UI Parameters { #other-swagger-ui-parameters }

View File

@ -18,7 +18,7 @@ The first step is to disable the automatic docs, as by default, those use the de
To disable them, set their URLs to `None` when creating your `FastAPI` app: To disable them, set their URLs to `None` when creating your `FastAPI` app:
{* ../../docs_src/custom_docs_ui/tutorial001.py hl[8] *} {* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *}
### Include the custom docs { #include-the-custom-docs } ### Include the custom docs { #include-the-custom-docs }
@ -34,7 +34,7 @@ You can reuse FastAPI's internal functions to create the HTML pages for the docs
And similarly for ReDoc... And similarly for ReDoc...
{* ../../docs_src/custom_docs_ui/tutorial001.py hl[2:6,11:19,22:24,27:33] *} {* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *}
/// tip /// tip
@ -50,7 +50,7 @@ Swagger UI will handle it behind the scenes for you, but it needs this "redirect
Now, to be able to test that everything works, create a *path operation*: Now, to be able to test that everything works, create a *path operation*:
{* ../../docs_src/custom_docs_ui/tutorial001.py hl[36:38] *} {* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *}
### Test it { #test-it } ### Test it { #test-it }
@ -118,7 +118,7 @@ After that, your file structure could look like:
* Import `StaticFiles`. * Import `StaticFiles`.
* "Mount" a `StaticFiles()` instance in a specific path. * "Mount" a `StaticFiles()` instance in a specific path.
{* ../../docs_src/custom_docs_ui/tutorial002.py hl[7,11] *} {* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *}
### Test the static files { #test-the-static-files } ### Test the static files { #test-the-static-files }
@ -144,7 +144,7 @@ The same as when using a custom CDN, the first step is to disable the automatic
To disable them, set their URLs to `None` when creating your `FastAPI` app: To disable them, set their URLs to `None` when creating your `FastAPI` app:
{* ../../docs_src/custom_docs_ui/tutorial002.py hl[9] *} {* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *}
### Include the custom docs for static files { #include-the-custom-docs-for-static-files } ### Include the custom docs for static files { #include-the-custom-docs-for-static-files }
@ -160,7 +160,7 @@ Again, you can reuse FastAPI's internal functions to create the HTML pages for t
And similarly for ReDoc... And similarly for ReDoc...
{* ../../docs_src/custom_docs_ui/tutorial002.py hl[2:6,14:22,25:27,30:36] *} {* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *}
/// tip /// tip
@ -176,7 +176,7 @@ Swagger UI will handle it behind the scenes for you, but it needs this "redirect
Now, to be able to test that everything works, create a *path operation*: Now, to be able to test that everything works, create a *path operation*:
{* ../../docs_src/custom_docs_ui/tutorial002.py hl[39:41] *} {* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *}
### Test Static Files UI { #test-static-files-ui } ### Test Static Files UI { #test-static-files-ui }

View File

@ -43,19 +43,19 @@ For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/doc
First, write all your **FastAPI** application as normally: First, write all your **FastAPI** application as normally:
{* ../../docs_src/extending_openapi/tutorial001.py hl[1,4,7:9] *} {* ../../docs_src/extending_openapi/tutorial001_py39.py hl[1,4,7:9] *}
### Generate the OpenAPI schema { #generate-the-openapi-schema } ### Generate the OpenAPI schema { #generate-the-openapi-schema }
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function: Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
{* ../../docs_src/extending_openapi/tutorial001.py hl[2,15:21] *} {* ../../docs_src/extending_openapi/tutorial001_py39.py hl[2,15:21] *}
### Modify the OpenAPI schema { #modify-the-openapi-schema } ### Modify the OpenAPI schema { #modify-the-openapi-schema }
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema: Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
{* ../../docs_src/extending_openapi/tutorial001.py hl[22:24] *} {* ../../docs_src/extending_openapi/tutorial001_py39.py hl[22:24] *}
### Cache the OpenAPI schema { #cache-the-openapi-schema } ### Cache the OpenAPI schema { #cache-the-openapi-schema }
@ -65,13 +65,13 @@ That way, your application won't have to generate the schema every time a user o
It will be generated only once, and then the same cached schema will be used for the next requests. It will be generated only once, and then the same cached schema will be used for the next requests.
{* ../../docs_src/extending_openapi/tutorial001.py hl[13:14,25:26] *} {* ../../docs_src/extending_openapi/tutorial001_py39.py hl[13:14,25:26] *}
### Override the method { #override-the-method } ### Override the method { #override-the-method }
Now you can replace the `.openapi()` method with your new function. Now you can replace the `.openapi()` method with your new function.
{* ../../docs_src/extending_openapi/tutorial001.py hl[29] *} {* ../../docs_src/extending_openapi/tutorial001_py39.py hl[29] *}
### Check it { #check-it } ### Check it { #check-it }

View File

@ -35,7 +35,7 @@ Depending on your use case, you might prefer to use a different library, but if
Here's a small preview of how you could integrate Strawberry with FastAPI: Here's a small preview of how you could integrate Strawberry with FastAPI:
{* ../../docs_src/graphql/tutorial001.py hl[3,22,25] *} {* ../../docs_src/graphql/tutorial001_py39.py hl[3,22,25] *}
You can learn more about Strawberry in the <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry documentation</a>. You can learn more about Strawberry in the <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry documentation</a>.

View File

@ -22,7 +22,7 @@ If you are a Python expert, and you already know everything about type hints, sk
Let's start with a simple example: Let's start with a simple example:
{* ../../docs_src/python_types/tutorial001.py *} {* ../../docs_src/python_types/tutorial001_py39.py *}
Calling this program outputs: Calling this program outputs:
@ -36,7 +36,7 @@ The function does the following:
* Converts the first letter of each one to upper case with `title()`. * Converts the first letter of each one to upper case with `title()`.
* <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> them with a space in the middle. * <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> them with a space in the middle.
{* ../../docs_src/python_types/tutorial001.py hl[2] *} {* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
### Edit it { #edit-it } ### Edit it { #edit-it }
@ -78,7 +78,7 @@ That's it.
Those are the "type hints": Those are the "type hints":
{* ../../docs_src/python_types/tutorial002.py hl[1] *} {* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
That is not the same as declaring default values like would be with: That is not the same as declaring default values like would be with:
@ -106,7 +106,7 @@ With that, you can scroll, seeing the options, until you find the one that "ring
Check this function, it already has type hints: Check this function, it already has type hints:
{* ../../docs_src/python_types/tutorial003.py hl[1] *} {* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
Because the editor knows the types of the variables, you don't only get completion, you also get error checks: Because the editor knows the types of the variables, you don't only get completion, you also get error checks:
@ -114,7 +114,7 @@ Because the editor knows the types of the variables, you don't only get completi
Now you know that you have to fix it, convert `age` to a string with `str(age)`: Now you know that you have to fix it, convert `age` to a string with `str(age)`:
{* ../../docs_src/python_types/tutorial004.py hl[2] *} {* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
## Declaring types { #declaring-types } ## Declaring types { #declaring-types }
@ -133,7 +133,7 @@ You can use, for example:
* `bool` * `bool`
* `bytes` * `bytes`
{* ../../docs_src/python_types/tutorial005.py hl[1] *} {* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
### Generic types with type parameters { #generic-types-with-type-parameters } ### Generic types with type parameters { #generic-types-with-type-parameters }
@ -161,56 +161,24 @@ If you can use the **latest versions of Python**, use the examples for the lates
For example, let's define a variable to be a `list` of `str`. For example, let's define a variable to be a `list` of `str`.
//// tab | Python 3.9+
Declare the variable, with the same colon (`:`) syntax. Declare the variable, with the same colon (`:`) syntax.
As the type, put `list`. As the type, put `list`.
As the list is a type that contains some internal types, you put them in square brackets: As the list is a type that contains some internal types, you put them in square brackets:
```Python hl_lines="1" {* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
{!> ../../docs_src/python_types/tutorial006_py39.py!}
```
////
//// tab | Python 3.8+
From `typing`, import `List` (with a capital `L`):
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial006.py!}
```
Declare the variable, with the same colon (`:`) syntax.
As the type, put the `List` that you imported from `typing`.
As the list is a type that contains some internal types, you put them in square brackets:
```Python hl_lines="4"
{!> ../../docs_src/python_types/tutorial006.py!}
```
////
/// info /// info
Those internal types in the square brackets are called "type parameters". Those internal types in the square brackets are called "type parameters".
In this case, `str` is the type parameter passed to `List` (or `list` in Python 3.9 and above). In this case, `str` is the type parameter passed to `list`.
/// ///
That means: "the variable `items` is a `list`, and each of the items in this list is a `str`". That means: "the variable `items` is a `list`, and each of the items in this list is a `str`".
/// tip
If you use Python 3.9 or above, you don't have to import `List` from `typing`, you can use the same regular `list` type instead.
///
By doing that, your editor can provide support even while processing items from the list: By doing that, your editor can provide support even while processing items from the list:
<img src="/img/python-types/image05.png"> <img src="/img/python-types/image05.png">
@ -225,21 +193,7 @@ And still, the editor knows it is a `str`, and provides support for that.
You would do the same to declare `tuple`s and `set`s: You would do the same to declare `tuple`s and `set`s:
//// tab | Python 3.9+ {* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial007_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial007.py!}
```
////
This means: This means:
@ -254,21 +208,7 @@ The first type parameter is for the keys of the `dict`.
The second type parameter is for the values of the `dict`: The second type parameter is for the values of the `dict`:
//// tab | Python 3.9+ {* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial008.py!}
```
////
This means: This means:
@ -292,10 +232,10 @@ In Python 3.10 there's also a **new syntax** where you can put the possible type
//// ////
//// tab | Python 3.8+ //// tab | Python 3.9+
```Python hl_lines="1 4" ```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial008b.py!} {!> ../../docs_src/python_types/tutorial008b_py39.py!}
``` ```
//// ////
@ -309,7 +249,7 @@ You can declare that a value could have a type, like `str`, but that it could al
In Python 3.6 and above (including Python 3.10) you can declare it by importing and using `Optional` from the `typing` module. In Python 3.6 and above (including Python 3.10) you can declare it by importing and using `Optional` from the `typing` module.
```Python hl_lines="1 4" ```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009.py!} {!../../docs_src/python_types/tutorial009_py39.py!}
``` ```
Using `Optional[str]` instead of just `str` will let the editor help you detect errors where you could be assuming that a value is always a `str`, when it could actually be `None` too. Using `Optional[str]` instead of just `str` will let the editor help you detect errors where you could be assuming that a value is always a `str`, when it could actually be `None` too.
@ -326,18 +266,18 @@ This also means that in Python 3.10, you can use `Something | None`:
//// ////
//// tab | Python 3.8+ //// tab | Python 3.9+
```Python hl_lines="1 4" ```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009.py!} {!> ../../docs_src/python_types/tutorial009_py39.py!}
``` ```
//// ////
//// tab | Python 3.8+ alternative //// tab | Python 3.9+ alternative
```Python hl_lines="1 4" ```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009b.py!} {!> ../../docs_src/python_types/tutorial009b_py39.py!}
``` ```
//// ////
@ -357,7 +297,7 @@ It's just about the words and names. But those words can affect how you and your
As an example, let's take this function: As an example, let's take this function:
{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} {* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter: The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter:
@ -390,10 +330,10 @@ You can use the same builtin types as generics (with square brackets and types i
* `set` * `set`
* `dict` * `dict`
And the same as with Python 3.8, from the `typing` module: And the same as with previous Python versions, from the `typing` module:
* `Union` * `Union`
* `Optional` (the same as with Python 3.8) * `Optional`
* ...and others. * ...and others.
In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</abbr> to declare unions of types, that's a lot better and simpler. In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</abbr> to declare unions of types, that's a lot better and simpler.
@ -409,7 +349,7 @@ You can use the same builtin types as generics (with square brackets and types i
* `set` * `set`
* `dict` * `dict`
And the same as with Python 3.8, from the `typing` module: And generics from the `typing` module:
* `Union` * `Union`
* `Optional` * `Optional`
@ -417,29 +357,17 @@ And the same as with Python 3.8, from the `typing` module:
//// ////
//// tab | Python 3.8+
* `List`
* `Tuple`
* `Set`
* `Dict`
* `Union`
* `Optional`
* ...and others.
////
### Classes as types { #classes-as-types } ### Classes as types { #classes-as-types }
You can also declare a class as the type of a variable. You can also declare a class as the type of a variable.
Let's say you have a class `Person`, with a name: Let's say you have a class `Person`, with a name:
{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} {* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
Then you can declare a variable to be of type `Person`: Then you can declare a variable to be of type `Person`:
{* ../../docs_src/python_types/tutorial010.py hl[6] *} {* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
And then, again, you get all the editor support: And then, again, you get all the editor support:
@ -463,29 +391,7 @@ And you get all the editor support with that resulting object.
An example from the official Pydantic docs: An example from the official Pydantic docs:
//// tab | Python 3.10+ {* ../../docs_src/python_types/tutorial011_py310.py *}
```Python
{!> ../../docs_src/python_types/tutorial011_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!> ../../docs_src/python_types/tutorial011_py39.py!}
```
////
//// tab | Python 3.8+
```Python
{!> ../../docs_src/python_types/tutorial011.py!}
```
////
/// info /// info
@ -507,27 +413,9 @@ Pydantic has a special behavior when you use `Optional` or `Union[Something, Non
Python also has a feature that allows putting **additional <abbr title="Data about the data, in this case, information about the type, e.g. a description.">metadata</abbr>** in these type hints using `Annotated`. Python also has a feature that allows putting **additional <abbr title="Data about the data, in this case, information about the type, e.g. a description.">metadata</abbr>** in these type hints using `Annotated`.
//// tab | Python 3.9+ Since Python 3.9, `Annotated` is a part of the standard library, so you can import it from `typing`.
In Python 3.9, `Annotated` is part of the standard library, so you can import it from `typing`. {* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial013_py39.py!}
```
////
//// tab | Python 3.8+
In versions below Python 3.9, you import `Annotated` from `typing_extensions`.
It will already be installed with **FastAPI**.
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial013.py!}
```
////
Python itself doesn't do anything with this `Annotated`. And for editors and other tools, the type is still `str`. Python itself doesn't do anything with this `Annotated`. And for editors and other tools, the type is still `str`.

View File

@ -15,7 +15,7 @@ This includes, for example:
First, import `BackgroundTasks` and define a parameter in your *path operation function* with a type declaration of `BackgroundTasks`: First, import `BackgroundTasks` and define a parameter in your *path operation function* with a type declaration of `BackgroundTasks`:
{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *} {* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
**FastAPI** will create the object of type `BackgroundTasks` for you and pass it as that parameter. **FastAPI** will create the object of type `BackgroundTasks` for you and pass it as that parameter.
@ -31,13 +31,13 @@ In this case, the task function will write to a file (simulating sending an emai
And as the write operation doesn't use `async` and `await`, we define the function with normal `def`: And as the write operation doesn't use `async` and `await`, we define the function with normal `def`:
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *} {* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
## Add the background task { #add-the-background-task } ## Add the background task { #add-the-background-task }
Inside of your *path operation function*, pass your task function to the *background tasks* object with the method `.add_task()`: Inside of your *path operation function*, pass your task function to the *background tasks* object with the method `.add_task()`:
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *} {* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
`.add_task()` receives as arguments: `.add_task()` receives as arguments:

View File

@ -14,35 +14,15 @@ This will make `tags` be a list, although it doesn't declare the type of the ele
But Python has a specific way to declare lists with internal types, or "type parameters": But Python has a specific way to declare lists with internal types, or "type parameters":
### Import typing's `List` { #import-typings-list }
In Python 3.9 and above you can use the standard `list` to declare these type annotations as we'll see below. 💡
But in Python versions before 3.9 (3.6 and above), you first need to import `List` from standard Python's `typing` module:
{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
### Declare a `list` with a type parameter { #declare-a-list-with-a-type-parameter } ### Declare a `list` with a type parameter { #declare-a-list-with-a-type-parameter }
To declare types that have type parameters (internal types), like `list`, `dict`, `tuple`: To declare types that have type parameters (internal types), like `list`, `dict`, `tuple`,
pass the internal type(s) as "type parameters" using square brackets: `[` and `]`
* If you are in a Python version lower than 3.9, import their equivalent version from the `typing` module
* Pass the internal type(s) as "type parameters" using square brackets: `[` and `]`
In Python 3.9 it would be:
```Python ```Python
my_list: list[str] my_list: list[str]
``` ```
In versions of Python before 3.9, it would be:
```Python
from typing import List
my_list: List[str]
```
That's all standard Python syntax for type declarations. That's all standard Python syntax for type declarations.
Use that same standard syntax for model attributes with internal types. Use that same standard syntax for model attributes with internal types.
@ -178,12 +158,6 @@ Notice how `Offer` has a list of `Item`s, which in turn have an optional list of
If the top level value of the JSON body you expect is a JSON `array` (a Python `list`), you can declare the type in the parameter of the function, the same as in Pydantic models: If the top level value of the JSON body you expect is a JSON `array` (a Python `list`), you can declare the type in the parameter of the function, the same as in Pydantic models:
```Python
images: List[Image]
```
or in Python 3.9 and above:
```Python ```Python
images: list[Image] images: list[Image]
``` ```

View File

@ -46,7 +46,7 @@ You can also specify whether your backend allows:
* Specific HTTP methods (`POST`, `PUT`) or all of them with the wildcard `"*"`. * Specific HTTP methods (`POST`, `PUT`) or all of them with the wildcard `"*"`.
* Specific HTTP headers or all of them with the wildcard `"*"`. * Specific HTTP headers or all of them with the wildcard `"*"`.
{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *} {* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
The default parameters used by the `CORSMiddleware` implementation are restrictive by default, so you'll need to explicitly enable particular origins, methods, or headers, in order for browsers to be permitted to use them in a Cross-Domain context. The default parameters used by the `CORSMiddleware` implementation are restrictive by default, so you'll need to explicitly enable particular origins, methods, or headers, in order for browsers to be permitted to use them in a Cross-Domain context.

View File

@ -6,7 +6,7 @@ You can connect the debugger in your editor, for example with Visual Studio Code
In your FastAPI application, import and run `uvicorn` directly: In your FastAPI application, import and run `uvicorn` directly:
{* ../../docs_src/debugging/tutorial001.py hl[1,15] *} {* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
### About `__name__ == "__main__"` { #about-name-main } ### About `__name__ == "__main__"` { #about-name-main }

View File

@ -29,15 +29,15 @@ For example, you could use this to create a database session and close it after
Only the code prior to and including the `yield` statement is executed before creating a response: Only the code prior to and including the `yield` statement is executed before creating a response:
{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *} {* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *}
The yielded value is what is injected into *path operations* and other dependencies: The yielded value is what is injected into *path operations* and other dependencies:
{* ../../docs_src/dependencies/tutorial007.py hl[4] *} {* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *}
The code following the `yield` statement is executed after the response: The code following the `yield` statement is executed after the response:
{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *} {* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *}
/// tip /// tip
@ -57,7 +57,7 @@ So, you can look for that specific exception inside the dependency with `except
In the same way, you can use `finally` to make sure the exit steps are executed, no matter if there was an exception or not. In the same way, you can use `finally` to make sure the exit steps are executed, no matter if there was an exception or not.
{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *} {* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *}
## Sub-dependencies with `yield` { #sub-dependencies-with-yield } ## Sub-dependencies with `yield` { #sub-dependencies-with-yield }
@ -269,7 +269,7 @@ In Python, you can create Context Managers by <a href="https://docs.python.org/3
You can also use them inside of **FastAPI** dependencies with `yield` by using You can also use them inside of **FastAPI** dependencies with `yield` by using
`with` or `async with` statements inside of the dependency function: `with` or `async with` statements inside of the dependency function:
{* ../../docs_src/dependencies/tutorial010.py hl[1:9,13] *} {* ../../docs_src/dependencies/tutorial010_py39.py hl[1:9,13] *}
/// tip /// tip

View File

@ -6,7 +6,7 @@ Similar to the way you can [add `dependencies` to the *path operation decorators
In that case, they will be applied to all the *path operations* in the application: In that case, they will be applied to all the *path operations* in the application:
{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[16] *} {* ../../docs_src/dependencies/tutorial012_an_py39.py hl[17] *}
And all the ideas in the section about [adding `dependencies` to the *path operation decorators*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} still apply, but in this case, to all of the *path operations* in the app. And all the ideas in the section about [adding `dependencies` to the *path operation decorators*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} still apply, but in this case, to all of the *path operations* in the app.

View File

@ -2,7 +2,7 @@
The simplest FastAPI file could look like this: The simplest FastAPI file could look like this:
{* ../../docs_src/first_steps/tutorial001.py *} {* ../../docs_src/first_steps/tutorial001_py39.py *}
Copy that to a file `main.py`. Copy that to a file `main.py`.
@ -183,7 +183,7 @@ That's it! Now you can access your app at that URL. ✨
### Step 1: import `FastAPI` { #step-1-import-fastapi } ### Step 1: import `FastAPI` { #step-1-import-fastapi }
{* ../../docs_src/first_steps/tutorial001.py hl[1] *} {* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
`FastAPI` is a Python class that provides all the functionality for your API. `FastAPI` is a Python class that provides all the functionality for your API.
@ -197,7 +197,7 @@ You can use all the <a href="https://www.starlette.dev/" class="external-link" t
### Step 2: create a `FastAPI` "instance" { #step-2-create-a-fastapi-instance } ### Step 2: create a `FastAPI` "instance" { #step-2-create-a-fastapi-instance }
{* ../../docs_src/first_steps/tutorial001.py hl[3] *} {* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
Here the `app` variable will be an "instance" of the class `FastAPI`. Here the `app` variable will be an "instance" of the class `FastAPI`.
@ -266,7 +266,7 @@ We are going to call them "**operations**" too.
#### Define a *path operation decorator* { #define-a-path-operation-decorator } #### Define a *path operation decorator* { #define-a-path-operation-decorator }
{* ../../docs_src/first_steps/tutorial001.py hl[6] *} {* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
The `@app.get("/")` tells **FastAPI** that the function right below is in charge of handling requests that go to: The `@app.get("/")` tells **FastAPI** that the function right below is in charge of handling requests that go to:
@ -320,7 +320,7 @@ This is our "**path operation function**":
* **operation**: is `get`. * **operation**: is `get`.
* **function**: is the function below the "decorator" (below `@app.get("/")`). * **function**: is the function below the "decorator" (below `@app.get("/")`).
{* ../../docs_src/first_steps/tutorial001.py hl[7] *} {* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
This is a Python function. This is a Python function.
@ -332,7 +332,7 @@ In this case, it is an `async` function.
You could also define it as a normal function instead of `async def`: You could also define it as a normal function instead of `async def`:
{* ../../docs_src/first_steps/tutorial003.py hl[7] *} {* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
/// note /// note
@ -342,7 +342,7 @@ If you don't know the difference, check the [Async: *"In a hurry?"*](../async.md
### Step 5: return the content { #step-5-return-the-content } ### Step 5: return the content { #step-5-return-the-content }
{* ../../docs_src/first_steps/tutorial001.py hl[8] *} {* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
You can return a `dict`, `list`, singular values as `str`, `int`, etc. You can return a `dict`, `list`, singular values as `str`, `int`, etc.

View File

@ -25,7 +25,7 @@ To return HTTP responses with errors to the client you use `HTTPException`.
### Import `HTTPException` { #import-httpexception } ### Import `HTTPException` { #import-httpexception }
{* ../../docs_src/handling_errors/tutorial001.py hl[1] *} {* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *}
### Raise an `HTTPException` in your code { #raise-an-httpexception-in-your-code } ### Raise an `HTTPException` in your code { #raise-an-httpexception-in-your-code }
@ -39,7 +39,7 @@ The benefit of raising an exception over returning a value will be more evident
In this example, when the client requests an item by an ID that doesn't exist, raise an exception with a status code of `404`: In this example, when the client requests an item by an ID that doesn't exist, raise an exception with a status code of `404`:
{* ../../docs_src/handling_errors/tutorial001.py hl[11] *} {* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *}
### The resulting response { #the-resulting-response } ### The resulting response { #the-resulting-response }
@ -77,7 +77,7 @@ You probably won't need to use it directly in your code.
But in case you needed it for an advanced scenario, you can add custom headers: But in case you needed it for an advanced scenario, you can add custom headers:
{* ../../docs_src/handling_errors/tutorial002.py hl[14] *} {* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *}
## Install custom exception handlers { #install-custom-exception-handlers } ## Install custom exception handlers { #install-custom-exception-handlers }
@ -89,7 +89,7 @@ And you want to handle this exception globally with FastAPI.
You could add a custom exception handler with `@app.exception_handler()`: You could add a custom exception handler with `@app.exception_handler()`:
{* ../../docs_src/handling_errors/tutorial003.py hl[5:7,13:18,24] *} {* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *}
Here, if you request `/unicorns/yolo`, the *path operation* will `raise` a `UnicornException`. Here, if you request `/unicorns/yolo`, the *path operation* will `raise` a `UnicornException`.
@ -127,7 +127,7 @@ To override it, import the `RequestValidationError` and use it with `@app.except
The exception handler will receive a `Request` and the exception. The exception handler will receive a `Request` and the exception.
{* ../../docs_src/handling_errors/tutorial004.py hl[2,14:19] *} {* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *}
Now, if you go to `/items/foo`, instead of getting the default JSON error with: Now, if you go to `/items/foo`, instead of getting the default JSON error with:
@ -159,7 +159,7 @@ The same way, you can override the `HTTPException` handler.
For example, you could want to return a plain text response instead of JSON for these errors: For example, you could want to return a plain text response instead of JSON for these errors:
{* ../../docs_src/handling_errors/tutorial004.py hl[3:4,9:11,25] *} {* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *}
/// note | Technical Details /// note | Technical Details
@ -183,7 +183,7 @@ The `RequestValidationError` contains the `body` it received with invalid data.
You could use it while developing your app to log the body and debug it, return it to the user, etc. You could use it while developing your app to log the body and debug it, return it to the user, etc.
{* ../../docs_src/handling_errors/tutorial005.py hl[14] *} {* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *}
Now try sending an invalid item like: Now try sending an invalid item like:
@ -239,6 +239,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
If you want to use the exception along with the same default exception handlers from **FastAPI**, you can import and reuse the default exception handlers from `fastapi.exception_handlers`: If you want to use the exception along with the same default exception handlers from **FastAPI**, you can import and reuse the default exception handlers from `fastapi.exception_handlers`:
{* ../../docs_src/handling_errors/tutorial006.py hl[2:5,15,21] *} {* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *}
In this example you are just printing the error with a very expressive message, but you get the idea. You can use the exception and then just reuse the default exception handlers. In this example you are just printing the error with a very expressive message, but you get the idea. You can use the exception and then just reuse the default exception handlers.

View File

@ -18,7 +18,7 @@ You can set the following fields that are used in the OpenAPI specification and
You can set them as follows: You can set them as follows:
{* ../../docs_src/metadata/tutorial001.py hl[3:16, 19:32] *} {* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *}
/// tip /// tip
@ -36,7 +36,7 @@ Since OpenAPI 3.1.0 and FastAPI 0.99.0, you can also set the `license_info` with
For example: For example:
{* ../../docs_src/metadata/tutorial001_1.py hl[31] *} {* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *}
## Metadata for tags { #metadata-for-tags } ## Metadata for tags { #metadata-for-tags }
@ -58,7 +58,7 @@ Let's try that in an example with tags for `users` and `items`.
Create metadata for your tags and pass it to the `openapi_tags` parameter: Create metadata for your tags and pass it to the `openapi_tags` parameter:
{* ../../docs_src/metadata/tutorial004.py hl[3:16,18] *} {* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *}
Notice that you can use Markdown inside of the descriptions, for example "login" will be shown in bold (**login**) and "fancy" will be shown in italics (_fancy_). Notice that you can use Markdown inside of the descriptions, for example "login" will be shown in bold (**login**) and "fancy" will be shown in italics (_fancy_).
@ -72,7 +72,7 @@ You don't have to add metadata for all the tags that you use.
Use the `tags` parameter with your *path operations* (and `APIRouter`s) to assign them to different tags: Use the `tags` parameter with your *path operations* (and `APIRouter`s) to assign them to different tags:
{* ../../docs_src/metadata/tutorial004.py hl[21,26] *} {* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *}
/// info /// info
@ -100,7 +100,7 @@ But you can configure it with the parameter `openapi_url`.
For example, to set it to be served at `/api/v1/openapi.json`: For example, to set it to be served at `/api/v1/openapi.json`:
{* ../../docs_src/metadata/tutorial002.py hl[3] *} {* ../../docs_src/metadata/tutorial002_py39.py hl[3] *}
If you want to disable the OpenAPI schema completely you can set `openapi_url=None`, that will also disable the documentation user interfaces that use it. If you want to disable the OpenAPI schema completely you can set `openapi_url=None`, that will also disable the documentation user interfaces that use it.
@ -117,4 +117,4 @@ You can configure the two documentation user interfaces included:
For example, to set Swagger UI to be served at `/documentation` and disable ReDoc: For example, to set Swagger UI to be served at `/documentation` and disable ReDoc:
{* ../../docs_src/metadata/tutorial003.py hl[3] *} {* ../../docs_src/metadata/tutorial003_py39.py hl[3] *}

View File

@ -31,7 +31,7 @@ The middleware function receives:
* Then it returns the `response` generated by the corresponding *path operation*. * Then it returns the `response` generated by the corresponding *path operation*.
* You can then further modify the `response` before returning it. * You can then further modify the `response` before returning it.
{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *} {* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *}
/// tip /// tip
@ -57,7 +57,7 @@ And also after the `response` is generated, before returning it.
For example, you could add a custom header `X-Process-Time` containing the time in seconds that it took to process the request and generate a response: For example, you could add a custom header `X-Process-Time` containing the time in seconds that it took to process the request and generate a response:
{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *} {* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *}
/// tip /// tip

View File

@ -46,7 +46,7 @@ In these cases, it could make sense to store the tags in an `Enum`.
**FastAPI** supports that the same way as with plain strings: **FastAPI** supports that the same way as with plain strings:
{* ../../docs_src/path_operation_configuration/tutorial002b.py hl[1,8:10,13,18] *} {* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *}
## Summary and description { #summary-and-description } ## Summary and description { #summary-and-description }
@ -92,7 +92,7 @@ So, if you don't provide one, **FastAPI** will automatically generate one of "Su
If you need to mark a *path operation* as <abbr title="obsolete, recommended not to use it">deprecated</abbr>, but without removing it, pass the parameter `deprecated`: If you need to mark a *path operation* as <abbr title="obsolete, recommended not to use it">deprecated</abbr>, but without removing it, pass the parameter `deprecated`:
{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *} {* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
It will be clearly marked as deprecated in the interactive docs: It will be clearly marked as deprecated in the interactive docs:

View File

@ -54,7 +54,7 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names,
So, you can declare your function as: So, you can declare your function as:
{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *} {* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
But keep in mind that if you use `Annotated`, you won't have this problem, it won't matter as you're not using the function parameter default values for `Query()` or `Path()`. But keep in mind that if you use `Annotated`, you won't have this problem, it won't matter as you're not using the function parameter default values for `Query()` or `Path()`.
@ -83,7 +83,7 @@ Pass `*`, as the first parameter of the function.
Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Even if they don't have a default value. Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Even if they don't have a default value.
{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *} {* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
### Better with `Annotated` { #better-with-annotated } ### Better with `Annotated` { #better-with-annotated }

View File

@ -2,7 +2,7 @@
You can declare path "parameters" or "variables" with the same syntax used by Python format strings: You can declare path "parameters" or "variables" with the same syntax used by Python format strings:
{* ../../docs_src/path_params/tutorial001.py hl[6:7] *} {* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
The value of the path parameter `item_id` will be passed to your function as the argument `item_id`. The value of the path parameter `item_id` will be passed to your function as the argument `item_id`.
@ -16,7 +16,7 @@ So, if you run this example and go to <a href="http://127.0.0.1:8000/items/foo"
You can declare the type of a path parameter in the function, using standard Python type annotations: You can declare the type of a path parameter in the function, using standard Python type annotations:
{* ../../docs_src/path_params/tutorial002.py hl[7] *} {* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
In this case, `item_id` is declared to be an `int`. In this case, `item_id` is declared to be an `int`.
@ -118,13 +118,13 @@ And then you can also have a path `/users/{user_id}` to get data about a specifi
Because *path operations* are evaluated in order, you need to make sure that the path for `/users/me` is declared before the one for `/users/{user_id}`: Because *path operations* are evaluated in order, you need to make sure that the path for `/users/me` is declared before the one for `/users/{user_id}`:
{* ../../docs_src/path_params/tutorial003.py hl[6,11] *} {* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
Otherwise, the path for `/users/{user_id}` would match also for `/users/me`, "thinking" that it's receiving a parameter `user_id` with a value of `"me"`. Otherwise, the path for `/users/{user_id}` would match also for `/users/me`, "thinking" that it's receiving a parameter `user_id` with a value of `"me"`.
Similarly, you cannot redefine a path operation: Similarly, you cannot redefine a path operation:
{* ../../docs_src/path_params/tutorial003b.py hl[6,11] *} {* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
The first one will always be used since the path matches first. The first one will always be used since the path matches first.
@ -140,7 +140,7 @@ By inheriting from `str` the API docs will be able to know that the values must
Then create class attributes with fixed values, which will be the available valid values: Then create class attributes with fixed values, which will be the available valid values:
{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *} {* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
/// info /// info
@ -158,7 +158,7 @@ If you are wondering, "AlexNet", "ResNet", and "LeNet" are just names of Machine
Then create a *path parameter* with a type annotation using the enum class you created (`ModelName`): Then create a *path parameter* with a type annotation using the enum class you created (`ModelName`):
{* ../../docs_src/path_params/tutorial005.py hl[16] *} {* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
### Check the docs { #check-the-docs } ### Check the docs { #check-the-docs }
@ -174,13 +174,13 @@ The value of the *path parameter* will be an *enumeration member*.
You can compare it with the *enumeration member* in your created enum `ModelName`: You can compare it with the *enumeration member* in your created enum `ModelName`:
{* ../../docs_src/path_params/tutorial005.py hl[17] *} {* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
#### Get the *enumeration value* { #get-the-enumeration-value } #### Get the *enumeration value* { #get-the-enumeration-value }
You can get the actual value (a `str` in this case) using `model_name.value`, or in general, `your_enum_member.value`: You can get the actual value (a `str` in this case) using `model_name.value`, or in general, `your_enum_member.value`:
{* ../../docs_src/path_params/tutorial005.py hl[20] *} {* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
/// tip /// tip
@ -194,7 +194,7 @@ You can return *enum members* from your *path operation*, even nested in a JSON
They will be converted to their corresponding values (strings in this case) before returning them to the client: They will be converted to their corresponding values (strings in this case) before returning them to the client:
{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *} {* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
In your client you will get a JSON response like: In your client you will get a JSON response like:
@ -233,7 +233,7 @@ In this case, the name of the parameter is `file_path`, and the last part, `:pat
So, you can use it with: So, you can use it with:
{* ../../docs_src/path_params/tutorial004.py hl[6] *} {* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
/// tip /// tip

View File

@ -2,7 +2,7 @@
When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters. When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters.
{* ../../docs_src/query_params/tutorial001.py hl[9] *} {* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
The query is the set of key-value pairs that go after the `?` in a URL, separated by `&` characters. The query is the set of key-value pairs that go after the `?` in a URL, separated by `&` characters.
@ -128,7 +128,7 @@ If you don't want to add a specific value but just make it optional, set the def
But when you want to make a query parameter required, you can just not declare any default value: But when you want to make a query parameter required, you can just not declare any default value:
{* ../../docs_src/query_params/tutorial005.py hl[6:7] *} {* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
Here the query parameter `needy` is a required query parameter of type `str`. Here the query parameter `needy` is a required query parameter of type `str`.

View File

@ -183,7 +183,7 @@ There might be cases where you return something that is not a valid Pydantic fie
The most common case would be [returning a Response directly as explained later in the advanced docs](../advanced/response-directly.md){.internal-link target=_blank}. The most common case would be [returning a Response directly as explained later in the advanced docs](../advanced/response-directly.md){.internal-link target=_blank}.
{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *} {* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
This simple case is handled automatically by FastAPI because the return type annotation is the class (or a subclass of) `Response`. This simple case is handled automatically by FastAPI because the return type annotation is the class (or a subclass of) `Response`.
@ -193,7 +193,7 @@ And tools will also be happy because both `RedirectResponse` and `JSONResponse`
You can also use a subclass of `Response` in the type annotation: You can also use a subclass of `Response` in the type annotation:
{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *} {* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
This will also work because `RedirectResponse` is a subclass of `Response`, and FastAPI will automatically handle this simple case. This will also work because `RedirectResponse` is a subclass of `Response`, and FastAPI will automatically handle this simple case.

View File

@ -8,7 +8,7 @@ The same way you can specify a response model, you can also declare the HTTP sta
* `@app.delete()` * `@app.delete()`
* etc. * etc.
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *} {* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
/// note /// note
@ -74,7 +74,7 @@ To know more about each status code and which code is for what, check the <a hre
Let's see the previous example again: Let's see the previous example again:
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *} {* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
`201` is the status code for "Created". `201` is the status code for "Created".
@ -82,7 +82,7 @@ But you don't have to memorize what each of these codes mean.
You can use the convenience variables from `fastapi.status`. You can use the convenience variables from `fastapi.status`.
{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *} {* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
They are just a convenience, they hold the same number, but that way you can use the editor's autocomplete to find them: They are just a convenience, they hold the same number, but that way you can use the editor's autocomplete to find them:

View File

@ -7,7 +7,7 @@ You can serve static files automatically from a directory using `StaticFiles`.
* Import `StaticFiles`. * Import `StaticFiles`.
* "Mount" a `StaticFiles()` instance in a specific path. * "Mount" a `StaticFiles()` instance in a specific path.
{* ../../docs_src/static_files/tutorial001.py hl[2,6] *} {* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
/// note | Technical Details /// note | Technical Details

View File

@ -30,7 +30,7 @@ Use the `TestClient` object the same way as you do with `httpx`.
Write simple `assert` statements with the standard Python expressions that you need to check (again, standard `pytest`). Write simple `assert` statements with the standard Python expressions that you need to check (again, standard `pytest`).
{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *} {* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
/// tip /// tip
@ -76,7 +76,7 @@ Let's say you have a file structure as described in [Bigger Applications](bigger
In the file `main.py` you have your **FastAPI** app: In the file `main.py` you have your **FastAPI** app:
{* ../../docs_src/app_testing/main.py *} {* ../../docs_src/app_testing/app_a_py39/main.py *}
### Testing file { #testing-file } ### Testing file { #testing-file }
@ -92,7 +92,7 @@ Then you could have a file `test_main.py` with your tests. It could live on the
Because this file is in the same package, you can use relative imports to import the object `app` from the `main` module (`main.py`): Because this file is in the same package, you can use relative imports to import the object `app` from the `main` module (`main.py`):
{* ../../docs_src/app_testing/test_main.py hl[3] *} {* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
...and have the code for the tests just like before. ...and have the code for the tests just like before.

View File

@ -1,26 +0,0 @@
from typing import Union
from fastapi import Body, FastAPI, status
from fastapi.responses import JSONResponse
from typing_extensions import Annotated
app = FastAPI()
items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
@app.put("/items/{item_id}")
async def upsert_item(
item_id: str,
name: Annotated[Union[str, None], Body()] = None,
size: Annotated[Union[int, None], Body()] = None,
):
if item_id in items:
item = items[item_id]
item["name"] = name
item["size"] = size
return item
else:
item = {"name": name, "size": size}
items[item_id] = item
return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)

View File

@ -1,39 +0,0 @@
from typing import Union
from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel
from typing_extensions import Annotated
fake_secret_token = "coneofsilence"
fake_db = {
"foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
"bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
}
app = FastAPI()
class Item(BaseModel):
id: str
title: str
description: Union[str, None] = None
@app.get("/items/{item_id}", response_model=Item)
async def read_main(item_id: str, x_token: Annotated[str, Header()]):
if x_token != fake_secret_token:
raise HTTPException(status_code=400, detail="Invalid X-Token header")
if item_id not in fake_db:
raise HTTPException(status_code=404, detail="Item not found")
return fake_db[item_id]
@app.post("/items/", response_model=Item)
async def create_item(item: Item, x_token: Annotated[str, Header()]):
if x_token != fake_secret_token:
raise HTTPException(status_code=400, detail="Invalid X-Token header")
if item.id in fake_db:
raise HTTPException(status_code=409, detail="Item already exists")
fake_db[item.id] = item
return item

View File

@ -1,65 +0,0 @@
from fastapi.testclient import TestClient
from .main import app
client = TestClient(app)
def test_read_item():
response = client.get("/items/foo", headers={"X-Token": "coneofsilence"})
assert response.status_code == 200
assert response.json() == {
"id": "foo",
"title": "Foo",
"description": "There goes my hero",
}
def test_read_item_bad_token():
response = client.get("/items/foo", headers={"X-Token": "hailhydra"})
assert response.status_code == 400
assert response.json() == {"detail": "Invalid X-Token header"}
def test_read_nonexistent_item():
response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
def test_create_item():
response = client.post(
"/items/",
headers={"X-Token": "coneofsilence"},
json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
)
assert response.status_code == 200
assert response.json() == {
"id": "foobar",
"title": "Foo Bar",
"description": "The Foo Barters",
}
def test_create_item_bad_token():
response = client.post(
"/items/",
headers={"X-Token": "hailhydra"},
json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"},
)
assert response.status_code == 400
assert response.json() == {"detail": "Invalid X-Token header"}
def test_create_existing_item():
response = client.post(
"/items/",
headers={"X-Token": "coneofsilence"},
json={
"id": "foo",
"title": "The Foo ID Stealers",
"description": "There goes my stealer",
},
)
assert response.status_code == 409
assert response.json() == {"detail": "Item already exists"}

View File

@ -1,20 +0,0 @@
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from typing_extensions import Annotated
app = FastAPI()
class HTTPBearer403(HTTPBearer):
def make_not_authenticated_error(self) -> HTTPException:
return HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail="Not authenticated"
)
CredentialsDep = Annotated[HTTPAuthorizationCredentials, Depends(HTTPBearer403())]
@app.get("/me")
def read_me(credentials: CredentialsDep):
return {"message": "You are authenticated", "token": credentials.credentials}

View File

@ -1,27 +0,0 @@
from typing import Union
from fastapi import BackgroundTasks, Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
def write_log(message: str):
with open("log.txt", mode="a") as log:
log.write(message)
def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None):
if q:
message = f"found query: {q}\n"
background_tasks.add_task(write_log, message)
return q
@app.post("/send-notification/{email}")
async def send_notification(
email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)]
):
message = f"message to {email}\n"
background_tasks.add_task(write_log, message)
return {"message": "Message sent"}

View File

@ -1,12 +0,0 @@
from fastapi import Header, HTTPException
from typing_extensions import Annotated
async def get_token_header(x_token: Annotated[str, Header()]):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
async def get_query_token(token: str):
if token != "jessica":
raise HTTPException(status_code=400, detail="No Jessica token provided")

View File

@ -1,8 +0,0 @@
from fastapi import APIRouter
router = APIRouter()
@router.post("/")
async def update_admin():
return {"message": "Admin getting schwifty"}

View File

@ -1,23 +0,0 @@
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}

View File

@ -1,38 +0,0 @@
from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
@router.put(
"/{item_id}",
tags=["custom"],
responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
if item_id != "plumbus":
raise HTTPException(
status_code=403, detail="You can only update the item: plumbus"
)
return {"item_id": item_id, "name": "The great Plumbus"}

View File

@ -1,18 +0,0 @@
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/", tags=["users"])
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
@router.get("/users/me", tags=["users"])
async def read_user_me():
return {"username": "fakecurrentuser"}
@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
return {"username": username}

View File

@ -1,22 +0,0 @@
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
from typing_extensions import Annotated
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = Field(
default=None, title="The description of the item", max_length=300
)
price: float = Field(gt=0, description="The price must be greater than zero")
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
results = {"item_id": item_id, "item": item}
return results

View File

@ -1,28 +0,0 @@
from typing import Union
from fastapi import FastAPI, Path
from pydantic import BaseModel
from typing_extensions import Annotated
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
q: Union[str, None] = None,
item: Union[Item, None] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if item:
results.update({"item": item})
return results

Some files were not shown because too many files have changed in this diff Show More