├── .gitignore
├── LICENSE
├── README.md
├── advanced
├── additional-responses.md
├── additional-status-codes.md
├── advanced-dependencies.md
├── async-sql-databases.md
├── custom-request-and-route.md
├── custom-response.md
├── events.md
├── extending-openapi.md
├── graphql.md
├── index.md
├── middleware.md
├── nosql-databases.md
├── openapi-callbacks.md
├── path-operation-advanced-configuration.md
├── response-change-status-code.md
├── response-cookies.md
├── response-directly.md
├── response-headers.md
├── security
│ ├── http-basic-auth.md
│ ├── index.md
│ └── oauth2-scopes.md
├── sql-databases-peewee.md
├── sub-applications-proxy.md
├── templates.md
├── testing-dependencies.md
├── testing-events.md
├── testing-websockets.md
├── using-request-directly.md
├── websockets.md
└── wsgi.md
├── alternatives.md
├── async.md
├── benchmarks.md
├── contributing.md
├── deployment.md
├── external-links.md
├── features.md
├── help-fastapi.md
├── history-design-future.md
├── img
├── favicon.png
├── github-social-preview.png
├── github-social-preview.svg
├── icon-transparent-bg.png
├── icon-white-bg.png
├── icon-white.svg
├── index
│ ├── index-01-swagger-ui-simple.png
│ ├── index-02-redoc-simple.png
│ ├── index-03-swagger-02.png
│ ├── index-04-swagger-03.png
│ ├── index-05-swagger-04.png
│ └── index-06-redoc-02.png
├── logo-margin
│ ├── logo-teal-vector.svg
│ ├── logo-teal.png
│ ├── logo-teal.svg
│ └── logo-white-bg.png
├── logo-teal-vector.svg
├── logo-teal.svg
├── pycharm-completion.png
├── python-types
│ ├── image01.png
│ ├── image02.png
│ ├── image03.png
│ ├── image04.png
│ ├── image05.png
│ └── image06.png
├── tutorial
│ ├── additional-responses
│ │ └── image01.png
│ ├── application-configuration
│ │ └── image01.png
│ ├── async-sql-databases
│ │ └── image01.png
│ ├── bigger-applications
│ │ └── image01.png
│ ├── body-fields
│ │ └── image01.png
│ ├── body-nested-models
│ │ └── image01.png
│ ├── body
│ │ ├── image01.png
│ │ ├── image02.png
│ │ ├── image03.png
│ │ ├── image04.png
│ │ └── image05.png
│ ├── custom-response
│ │ └── image01.png
│ ├── debugging
│ │ └── image01.png
│ ├── dependencies
│ │ ├── image01.png
│ │ └── image02.png
│ ├── extending-openapi
│ │ └── image01.png
│ ├── graphql
│ │ └── image01.png
│ ├── openapi-callbacks
│ │ └── image01.png
│ ├── path-operation-configuration
│ │ ├── image01.png
│ │ ├── image02.png
│ │ ├── image03.png
│ │ ├── image04.png
│ │ └── image05.png
│ ├── path-params
│ │ ├── image01.png
│ │ ├── image02.png
│ │ └── image03.png
│ ├── query-params-str-validations
│ │ ├── image01.png
│ │ └── image02.png
│ ├── response-model
│ │ ├── image01.png
│ │ └── image02.png
│ ├── response-status-code
│ │ ├── image01.png
│ │ └── image02.png
│ ├── security
│ │ ├── image01.png
│ │ ├── image02.png
│ │ ├── image03.png
│ │ ├── image04.png
│ │ ├── image05.png
│ │ ├── image06.png
│ │ ├── image07.png
│ │ ├── image08.png
│ │ ├── image09.png
│ │ ├── image10.png
│ │ ├── image11.png
│ │ └── image12.png
│ ├── sql-databases
│ │ ├── image01.png
│ │ └── image02.png
│ ├── sub-applications
│ │ ├── image01.png
│ │ └── image02.png
│ └── websockets
│ │ ├── image01.png
│ │ ├── image02.png
│ │ ├── image03.png
│ │ └── image04.png
└── vscode-completion.png
├── project-generation.md
├── python-types.md
├── release-notes.md
├── src
├── additional_responses
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ └── tutorial004.py
├── additional_status_codes
│ └── tutorial001.py
├── advanced_middleware
│ ├── tutorial001.py
│ ├── tutorial002.py
│ └── tutorial003.py
├── app_testing
│ ├── __init__.py
│ ├── main.py
│ ├── main_b.py
│ ├── test_main.py
│ ├── test_main_b.py
│ ├── tutorial001.py
│ ├── tutorial002.py
│ └── tutorial003.py
├── application_configuration
│ ├── tutorial001.py
│ ├── tutorial002.py
│ └── tutorial003.py
├── async_sql_databases
│ └── tutorial001.py
├── background_tasks
│ ├── tutorial001.py
│ └── tutorial002.py
├── bigger_applications
│ ├── __init__.py
│ └── app
│ │ ├── __init__.py
│ │ ├── main.py
│ │ └── routers
│ │ ├── __init__.py
│ │ ├── items.py
│ │ └── users.py
├── body
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ └── tutorial004.py
├── body_fields
│ ├── tutorial001.py
│ └── tutorial002.py
├── body_multiple_params
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ └── tutorial005.py
├── body_nested_models
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ ├── tutorial006.py
│ ├── tutorial007.py
│ ├── tutorial008.py
│ └── tutorial009.py
├── body_updates
│ ├── tutorial001.py
│ └── tutorial002.py
├── cookie_params
│ └── tutorial001.py
├── cors
│ └── tutorial001.py
├── custom_request_and_route
│ ├── tutorial001.py
│ ├── tutorial002.py
│ └── tutorial003.py
├── custom_response
│ ├── tutorial001.py
│ ├── tutorial001b.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ ├── tutorial006.py
│ ├── tutorial007.py
│ ├── tutorial008.py
│ └── tutorial009.py
├── debugging
│ └── tutorial001.py
├── dependencies
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ ├── tutorial006.py
│ ├── tutorial007.py
│ ├── tutorial008.py
│ ├── tutorial009.py
│ ├── tutorial010.py
│ └── tutorial011.py
├── dependency_testing
│ └── tutorial001.py
├── encoder
│ └── tutorial001.py
├── events
│ ├── tutorial001.py
│ └── tutorial002.py
├── extending_openapi
│ ├── tutorial001.py
│ └── tutorial002.py
├── extra_data_types
│ └── tutorial001.py
├── extra_models
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ └── tutorial005.py
├── first_steps
│ ├── tutorial001.py
│ ├── tutorial002.py
│ └── tutorial003.py
├── graphql
│ └── tutorial001.py
├── handling_errors
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ └── tutorial006.py
├── header_params
│ ├── tutorial001.py
│ ├── tutorial002.py
│ └── tutorial003.py
├── middleware
│ └── tutorial001.py
├── nosql_databases
│ └── tutorial001.py
├── openapi_callbacks
│ └── tutorial001.py
├── path_operation_advanced_configuration
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ └── tutorial004.py
├── path_operation_configuration
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ └── tutorial006.py
├── path_params
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ └── tutorial005.py
├── path_params_numeric_validations
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ └── tutorial006.py
├── python_types
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ ├── tutorial006.py
│ ├── tutorial007.py
│ ├── tutorial008.py
│ ├── tutorial009.py
│ └── tutorial010.py
├── query_params
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ ├── tutorial006.py
│ └── tutorial007.py
├── query_params_str_validations
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ ├── tutorial006.py
│ ├── tutorial007.py
│ ├── tutorial008.py
│ ├── tutorial009.py
│ ├── tutorial010.py
│ ├── tutorial011.py
│ ├── tutorial012.py
│ └── tutorial013.py
├── request_files
│ ├── tutorial001.py
│ └── tutorial002.py
├── request_forms
│ └── tutorial001.py
├── request_forms_and_files
│ └── tutorial001.py
├── response_change_status_code
│ └── tutorial001.py
├── response_cookies
│ ├── tutorial001.py
│ └── tutorial002.py
├── response_directly
│ ├── tutorial001.py
│ └── tutorial002.py
├── response_headers
│ ├── tutorial001.py
│ └── tutorial002.py
├── response_model
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ └── tutorial006.py
├── response_status_code
│ ├── tutorial001.py
│ └── tutorial002.py
├── security
│ ├── tutorial001.py
│ ├── tutorial002.py
│ ├── tutorial003.py
│ ├── tutorial004.py
│ ├── tutorial005.py
│ ├── tutorial006.py
│ └── tutorial007.py
├── sql_databases
│ ├── __init__.py
│ └── sql_app
│ │ ├── __init__.py
│ │ ├── alt_main.py
│ │ ├── crud.py
│ │ ├── database.py
│ │ ├── main.py
│ │ ├── models.py
│ │ └── schemas.py
├── sql_databases_peewee
│ ├── __init__.py
│ └── sql_app
│ │ ├── __init__.py
│ │ ├── crud.py
│ │ ├── database.py
│ │ ├── main.py
│ │ ├── models.py
│ │ └── schemas.py
├── static_files
│ └── tutorial001.py
├── sub_applications
│ └── tutorial001.py
├── templates
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── item.html
│ └── tutorial001.py
├── using_request_directly
│ └── tutorial001.py
├── websockets
│ ├── __init__.py
│ ├── tutorial001.py
│ └── tutorial002.py
└── wsgi
│ └── tutorial001.py
└── tutorial
├── README.md
├── application-configuration.md
├── background-tasks.md
├── bigger-applications.md
├── body-fields.md
├── body-multiple-params.md
├── body-nested-models.md
├── body-updates.md
├── body.md
├── cookie-params.md
├── cors.md
├── debugging.md
├── dependencies
├── classes-as-dependencies.md
├── dependencies-in-path-operation-decorators.md
├── dependencies-with-yield.md
├── index.md
└── sub-dependencies.md
├── encoder.md
├── extra-data-types.md
├── extra-models.md
├── first-steps.md
├── handling-errors.md
├── header-params.md
├── middleware.md
├── path-operation-configuration.md
├── path-params-numeric-validations.md
├── path-params.md
├── query-params-str-validations.md
├── query-params.md
├── request-files.md
├── request-forms-and-files.md
├── request-forms.md
├── response-model.md
├── response-status-code.md
├── security
├── first-steps.md
├── get-current-user.md
├── index.md
├── oauth2-jwt.md
└── simple-oauth2.md
├── sql-databases.md
├── static-files.md
└── testing.md
/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/.gitignore
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 ApacheCN
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/advanced/additional-status-codes.md:
--------------------------------------------------------------------------------
1 | By default, **FastAPI** will return the responses using a `JSONResponse`, putting the content you return from your *path operation* inside of that `JSONResponse`.
2 |
3 | It will use the default status code or the one you set in your *path operation*.
4 |
5 | ## Additional status codes
6 |
7 | If you want to return additional status codes apart from the main one, you can do that by returning a `Response` directly, like a `JSONResponse`, and set the additional status code directly.
8 |
9 | For example, let's say that you want to have a *path operation* that allows to update items, and returns HTTP status codes of 200 "OK" when successful.
10 |
11 | But you also want it to accept new items. And when the items didn't exist before, it creates them, and returns an HTTP status code of 201 "Created".
12 |
13 | To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
14 |
15 | ```Python hl_lines="2 19"
16 | {!./src/additional_status_codes/tutorial001.py!}
17 | ```
18 |
19 | !!! warning
20 | When you return a `Response` directly, like in the example above, it will be returned directly.
21 |
22 | It won't be serialized with a model, etc.
23 |
24 | Make sure it has the data you want it to have, and that the values are valid JSON (if you are using `JSONResponse`).
25 |
26 | !!! note "Technical Details"
27 | You could also use `from starlette.responses import JSONResponse`.
28 |
29 | **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette. The same with `status`.
30 |
31 | ## OpenAPI and API docs
32 |
33 | If you return additional status codes and responses directly, they won't be included in the OpenAPI schema (the API docs), because FastAPI doesn't have a way to know beforehand what you are going to return.
34 |
35 | But you can document that in your code, using: [Additional Responses](additional-responses.md){.internal-link target=_blank}.
36 |
--------------------------------------------------------------------------------
/advanced/advanced-dependencies.md:
--------------------------------------------------------------------------------
1 | ## Parameterized dependencies
2 |
3 | All the dependencies we have seen are a fixed function or class.
4 |
5 | But there could be cases where you want to be able to set parameters on the dependency, without having to declare many different functions or classes.
6 |
7 | Let's imagine that we want to have a dependency that checks if the query parameter `q` contains some fixed content.
8 |
9 | But we want to be able to parameterize that fixed content.
10 |
11 | ## A "callable" instance
12 |
13 | In Python there's a way to make an instance of a class a "callable".
14 |
15 | Not the class itself (which is already a callable), but an instance of that class.
16 |
17 | To do that, we declare a method `__call__`:
18 |
19 | ```Python hl_lines="10"
20 | {!./src/dependencies/tutorial011.py!}
21 | ```
22 |
23 | In this case, this `__call__` is what **FastAPI** will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your *path operation function* later.
24 |
25 | ## Parameterize the instance
26 |
27 | And now, we can use `__init__` to declare the parameters of the instance that we can use to "parameterize" the dependency:
28 |
29 | ```Python hl_lines="7"
30 | {!./src/dependencies/tutorial011.py!}
31 | ```
32 |
33 | In this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code.
34 |
35 | ## Create an instance
36 |
37 | We could create an instance of this class with:
38 |
39 | ```Python hl_lines="16"
40 | {!./src/dependencies/tutorial011.py!}
41 | ```
42 |
43 | And that way we are able to "parameterize" our dependency, that now has `"bar"` inside of it, as the attribute `checker.fixed_content`.
44 |
45 | ## Use the instance as a dependency
46 |
47 | Then, we could use this `checker` in a `Depends(checker)`, instead of `Depends(FixedContentQueryChecker)`, because the dependency is the instance, `checker`, not the class itself.
48 |
49 | And when solving the dependency, **FastAPI** will call this `checker` like:
50 |
51 | ```Python
52 | checker(q="somequery")
53 | ```
54 |
55 | ...and pass whatever that returns as the value of the dependency in our *path operation function* as the parameter `fixed_content_included`:
56 |
57 | ```Python hl_lines="20"
58 | {!./src/dependencies/tutorial011.py!}
59 | ```
60 |
61 | !!! tip
62 | All this might seem contrived. And it might not be very clear how is it useful yet.
63 |
64 | These examples are intentionally simple, but show how it all works.
65 |
66 | In the chapters about security, there are utility functions that are implemented in this same way.
67 |
68 | If you understood all this, you already know how those utility tools for security work underneath.
69 |
--------------------------------------------------------------------------------
/advanced/events.md:
--------------------------------------------------------------------------------
1 |
2 | You can define event handlers (functions) that need to be executed before the application starts up, or when the application is shutting down.
3 |
4 | These functions can be declared with `async def` or normal `def`.
5 |
6 | ## `startup` event
7 |
8 | To add a function that should be run before the application starts, declare it with the event `"startup"`:
9 |
10 | ```Python hl_lines="8"
11 | {!./src/events/tutorial001.py!}
12 | ```
13 |
14 | In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values.
15 |
16 | You can add more than one event handler function.
17 |
18 | And your application won't start receiving requests until all the `startup` event handlers have completed.
19 |
20 | ## `shutdown` event
21 |
22 | To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`:
23 |
24 | ```Python hl_lines="6"
25 | {!./src/events/tutorial002.py!}
26 | ```
27 |
28 | Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`.
29 |
30 | !!! info
31 | In the `open()` function, the `mode="a"` means "append", so, the line will be added after whatever is on that file, without overwriting the previous contents.
32 |
33 | !!! tip
34 | Notice that in this case we are using a standard Python `open()` function that interacts with a file.
35 |
36 | So, it involves I/O (input/output), that requires "waiting" for things to be written to disk.
37 |
38 | But `open()` doesn't use `async` and `await`.
39 |
40 | So, we declare the event handler function with standard `def` instead of `async def`.
41 |
42 | !!! info
43 | You can read more about these event handlers in Starlette's Events' docs .
--------------------------------------------------------------------------------
/advanced/graphql.md:
--------------------------------------------------------------------------------
1 |
2 | **FastAPI** has optional support for GraphQL (provided by Starlette directly), using the `graphene` library.
3 |
4 | You can combine normal FastAPI *path operations* with GraphQL on the same application.
5 |
6 | ## Import and use `graphene`
7 |
8 | GraphQL is implemented with Graphene, you can check Graphene's docs for more details.
9 |
10 | Import `graphene` and define your GraphQL data:
11 |
12 | ```Python hl_lines="1 6 7 8 9 10"
13 | {!./src/graphql/tutorial001.py!}
14 | ```
15 |
16 | ## Add Starlette's `GraphQLApp`
17 |
18 | Then import and add Starlette's `GraphQLApp`:
19 |
20 | ```Python hl_lines="3 14"
21 | {!./src/graphql/tutorial001.py!}
22 | ```
23 |
24 | !!! info
25 | Here we are using `.add_route`, that is the way to add a route in Starlette (inherited by FastAPI) without declaring the specific operation (as would be with `.get()`, `.post()`, etc).
26 |
27 | ## Check it
28 |
29 | Run it with Uvicorn and open your browser at http://127.0.0.1:8000 .
30 |
31 | You will see GraphiQL web user interface:
32 |
33 |
34 |
35 | ## More details
36 |
37 | For more details, including:
38 |
39 | * Accessing request information
40 | * Adding background tasks
41 | * Using normal or async functions
42 |
43 | check the official Starlette GraphQL docs .
44 |
--------------------------------------------------------------------------------
/advanced/index.md:
--------------------------------------------------------------------------------
1 | ## Additional Features
2 |
3 | The main [Tutorial - User Guide](../tutorial/){.internal-link target=_blank} should be enough to give you a tour through all the main features of **FastAPI**.
4 |
5 | In the next sections you will see other options, configurations, and additional features.
6 |
7 | !!! tip
8 | The next sections are **not necessarily "advanced"**.
9 |
10 | And it's possible that for your use case, the solution is in one of them.
11 |
12 | ## Read the Tutorial first
13 |
14 | You could still use most of the features in **FastAPI** with the knowledge from the main [Tutorial - User Guide](../tutorial/){.internal-link target=_blank}.
15 |
16 | And the next sections assume you already read it, and assume that you know those main ideas.
17 |
--------------------------------------------------------------------------------
/advanced/path-operation-advanced-configuration.md:
--------------------------------------------------------------------------------
1 | ## OpenAPI operationId
2 |
3 | !!! warning
4 | If you are not an "expert" in OpenAPI, you probably don't need this.
5 |
6 | You can set the OpenAPI `operationId` to be used in your *path operation* with the parameter `operation_id`.
7 |
8 | You would have to make sure that it is unique for each operation.
9 |
10 | ```Python hl_lines="6"
11 | {!./src/path_operation_advanced_configuration/tutorial001.py!}
12 | ```
13 |
14 | ### Using the *path operation function* name as the operationId
15 |
16 | If you want to use your APIs' function names as `operationId`s, you can iterate over all of them and override each *path operation's* `operation_id` using their `APIRoute.name`.
17 |
18 | You should do it after adding all your *path operations*.
19 |
20 | ```Python hl_lines="2 12 13 14 15 16 17 18 19 20 21 24"
21 | {!./src/path_operation_advanced_configuration/tutorial002.py!}
22 | ```
23 |
24 | !!! tip
25 | If you manually call `app.openapi()`, you should update the `operationId`s before that.
26 |
27 | !!! warning
28 | If you do this, you have to make sure each one of your *path operation functions* has a unique name.
29 |
30 | Even if they are in different modules (Python files).
31 |
32 | ## Exclude from OpenAPI
33 |
34 | 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`;
35 |
36 | ```Python hl_lines="6"
37 | {!./src/path_operation_advanced_configuration/tutorial003.py!}
38 | ```
39 |
40 | ## Advanced description from docstring
41 |
42 | You can limit the lines used from the docstring of a *path operation function* for OpenAPI.
43 |
44 | Adding an `\f` (an escaped "form feed" character) causes **FastAPI** to truncate the output used for OpenAPI at this point.
45 |
46 | It won't show up in the documentation, but other tools (such as Sphinx) will be able to use the rest.
47 |
48 | ```Python hl_lines="19 20 21 22 23 24 25 26 27 28 29"
49 | {!./src/path_operation_advanced_configuration/tutorial004.py!}
50 | ```
51 |
--------------------------------------------------------------------------------
/advanced/response-change-status-code.md:
--------------------------------------------------------------------------------
1 | You probably read before that you can set a default [Response Status Code](../tutorial/response-status-code.md){.internal-link target=_blank}.
2 |
3 | But in some cases you need to return a different status code than the default.
4 |
5 | ## Use case
6 |
7 | For example, imagine that you want to return an HTTP status code of "OK" `200` by default.
8 |
9 | But if the data didn't exist, you want to create it, and return an HTTP status code of "CREATED" `201`.
10 |
11 | But you still want to be able to filter and convert the data you return with a `response_model`.
12 |
13 | For those cases, you can use a `Response` parameter.
14 |
15 | ## Use a `Response` parameter
16 |
17 | You can declare a parameter of type `Response` in your *path operation function* (as you can do for cookies and headers).
18 |
19 | And then you can set the `status_code` in that *temporal* response object.
20 |
21 | ```Python hl_lines="1 9 12"
22 | {!./src/response_change_status_code/tutorial001.py!}
23 | ```
24 |
25 | And then you can return any object you need, as you normally would (a `dict`, a database model, etc).
26 |
27 | And if you declared a `response_model`, it will still be used to filter and convert the object you returned.
28 |
29 | **FastAPI** will use that *temporal* response to extract the status code (also cookies and headers), and will put them in the final response that contains the value you returned, filtered by any `response_model`.
30 |
31 | You can also declare the `Response` parameter in dependencies, and set the status code in them. But have in mind that the last one to be set will win.
32 |
--------------------------------------------------------------------------------
/advanced/response-cookies.md:
--------------------------------------------------------------------------------
1 | ## Use a `Response` parameter
2 |
3 | You can declare a parameter of type `Response` in your *path operation function*.
4 |
5 | And then you can set cookies in that *temporal* response object.
6 |
7 | ```Python hl_lines="1 8 9"
8 | {!./src/response_cookies/tutorial002.py!}
9 | ```
10 |
11 | And then you can return any object you need, as you normally would (a `dict`, a database model, etc).
12 |
13 | And if you declared a `response_model`, it will still be used to filter and convert the object you returned.
14 |
15 | **FastAPI** will use that *temporal* response to extract the cookies (also headers and status code), and will put them in the final response that contains the value you returned, filtered by any `response_model`.
16 |
17 | You can also declare the `Response` parameter in dependencies, and set cookies (and headers) in them.
18 |
19 | ## Return a `Response` directly
20 |
21 | You can also create cookies when returning a `Response` directly in your code.
22 |
23 | To do that, you can create a response as described in [Return a Response Directly](response-directly.md){.internal-link target=_blank}.
24 |
25 | Then set Cookies in it, and then return it:
26 |
27 | ```Python hl_lines="10 11 12"
28 | {!./src/response_cookies/tutorial001.py!}
29 | ```
30 |
31 | !!! tip
32 | Have in mind that if you return a response directly instead of using the `Response` parameter, FastAPI will return it directly.
33 |
34 | So, you will have to make sure your data is of the correct type. E.g. it is compatible with JSON, if you are returning a `JSONResponse`.
35 |
36 | And also that you are not sending any data that should have been filtered by a `response_model`.
37 |
38 | ### More info
39 |
40 | !!! note "Technical Details"
41 | You could also use `from starlette.responses import Response` or `from starlette.responses import JSONResponse`.
42 |
43 | **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.
44 |
45 | And as the `Response` can be used frequently to set headers and cookies, **FastAPI** also provides it at `fastapi.Response`.
46 |
47 | To see all the available parameters and options, check the documentation in Starlette .
48 |
--------------------------------------------------------------------------------
/advanced/response-headers.md:
--------------------------------------------------------------------------------
1 | ## Use a `Response` parameter
2 |
3 | You can declare a parameter of type `Response` in your *path operation function* (as you can do for cookies).
4 |
5 | And then you can set headers in that *temporal* response object.
6 |
7 | ```Python hl_lines="1 7 8"
8 | {!./src/response_headers/tutorial002.py!}
9 | ```
10 |
11 | And then you can return any object you need, as you normally would (a `dict`, a database model, etc).
12 |
13 | And if you declared a `response_model`, it will still be used to filter and convert the object you returned.
14 |
15 | **FastAPI** will use that *temporal* response to extract the headers (also cookies and status code), and will put them in the final response that contains the value you returned, filtered by any `response_model`.
16 |
17 | You can also declare the `Response` parameter in dependencies, and set headers (and cookies) in them.
18 |
19 | ## Return a `Response` directly
20 |
21 | You can also add headers when you return a `Response` directly.
22 |
23 | 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:
24 |
25 | ```Python hl_lines="10 11 12"
26 | {!./src/response_headers/tutorial001.py!}
27 | ```
28 |
29 | !!! note "Technical Details"
30 | You could also use `from starlette.responses import Response` or `from starlette.responses import JSONResponse`.
31 |
32 | **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.
33 |
34 | And as the `Response` can be used frequently to set headers and cookies, **FastAPI** also provides it at `fastapi.Response`.
35 |
36 | ## Custom Headers
37 |
38 | Have in mind that custom proprietary headers can be added using the 'X-' prefix .
39 |
40 | But if you have custom headers that you want a client in a browser to be able to see, you need to add them to your CORS configurations (read more in [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), using the parameter `expose_headers` documented in Starlette's CORS docs .
41 |
--------------------------------------------------------------------------------
/advanced/security/index.md:
--------------------------------------------------------------------------------
1 | ## Additional Features
2 |
3 | There are some extra features to handle security apart from the ones covered in the [Tutorial - User Guide: Security](../../tutorial/security/){.internal-link target=_blank}.
4 |
5 | !!! tip
6 | The next sections are **not necessarily "advanced"**.
7 |
8 | And it's possible that for your use case, the solution is in one of them.
9 |
10 | ## Read the Tutorial first
11 |
12 | The next sections assume you already read the main [Tutorial - User Guide: Security](../../tutorial/security/){.internal-link target=_blank}.
13 |
14 | They are all based on the same concepts, but allow some extra functionalities.
15 |
--------------------------------------------------------------------------------
/advanced/templates.md:
--------------------------------------------------------------------------------
1 | You can use any template engine you want with **FastAPI**.
2 |
3 | A common election is Jinja2, the same one used by Flask and other tools.
4 |
5 | There are utilities to configure it easily that you can use directly in your **FastAPI** application (provided by Starlette).
6 |
7 | ## Install dependencies
8 |
9 | Install `jinja2`:
10 |
11 |
12 |
13 | ```console
14 | $ pip install jinja2
15 |
16 | ---> 100%
17 | ```
18 |
19 |
20 |
21 | If you need to also serve static files (as in this example), install `aiofiles`:
22 |
23 |
24 |
25 | ```console
26 | $ pip install aiofiles
27 |
28 | ---> 100%
29 | ```
30 |
31 |
32 |
33 | ## Using `Jinja2Templates`
34 |
35 | * Import `Jinja2Templates`.
36 | * Create a `templates` object that you can re-use later.
37 | * Declare a `Request` parameter in the *path operation* that will return a template.
38 | * Use the `templates` you created to render and return a `TemplateResponse`, passing the `request` as one of the key-value pairs in the Jinja2 "context".
39 |
40 | ```Python hl_lines="3 10 14 15"
41 | {!./src/templates/tutorial001.py!}
42 | ```
43 |
44 | !!! note
45 | Notice that you have to pass the `request` as part of the key-value pairs in the context for Jinja2. So, you also have to declare it in your *path operation*.
46 |
47 | !!! note "Technical Details"
48 | You could also use `from starlette.templating import Jinja2Templates`.
49 |
50 | **FastAPI** provides the same `starlette.templating` as `fastapi.templating` just as a convenience for you, the developer. But most of the available responses come directly from Starlette. The same with `Request` and `StaticFiles`.
51 |
52 | ## Writing templates
53 |
54 | Then you can write a template at `templates/item.html` with:
55 |
56 | ```jinja hl_lines="7"
57 | {!./src/templates/templates/item.html!}
58 | ```
59 |
60 | It will show the `id` taken from the "context" `dict` you passed:
61 |
62 | ```Python
63 | {"request": request, "id": id}
64 | ```
65 |
66 | ## Templates and static files
67 |
68 | And you can also use `url_for()` inside of the template, and use it, for example, with the `StaticFiles` you mounted.
69 |
70 | ```jinja hl_lines="4"
71 | {!./src/templates/templates/item.html!}
72 | ```
73 |
74 | In this example, it would link to a CSS file at `static/styles.css` with:
75 |
76 | ```CSS hl_lines="4"
77 | {!./src/templates/static/styles.css!}
78 | ```
79 |
80 | And because you are using `StaticFiles`, that CSS file would be served automatically by your **FastAPI** application at the URL `/static/styles.css`.
81 |
82 | ## More details
83 |
84 | For more details, including how to test templates, check Starlette's docs on templates .
85 |
--------------------------------------------------------------------------------
/advanced/testing-events.md:
--------------------------------------------------------------------------------
1 | ## Testing Events, `startup` and `shutdown`
2 |
3 | When you need your event handlers (`startup` and `shutdown`) to run in your tests, you can use the `TestClient` with a `with` statement:
4 |
5 | ```Python hl_lines="9 10 11 12 20 21 22 23 24"
6 | {!./src/app_testing/tutorial003.py!}
7 | ```
--------------------------------------------------------------------------------
/advanced/testing-websockets.md:
--------------------------------------------------------------------------------
1 | ## Testing WebSockets
2 |
3 | You can use the same `TestClient` to test WebSockets.
4 |
5 | For this, you use the `TestClient` in a `with` statement, connecting to the WebSocket:
6 |
7 | ```Python hl_lines="27 28 29 30 31"
8 | {!./src/app_testing/tutorial002.py!}
9 | ```
10 |
--------------------------------------------------------------------------------
/advanced/using-request-directly.md:
--------------------------------------------------------------------------------
1 | Up to now, you have been declaring the parts of the request that you need with their types.
2 |
3 | Taking data from:
4 |
5 | * The path as parameters.
6 | * Headers.
7 | * Cookies.
8 | * etc.
9 |
10 | And by doing so, **FastAPI** is validating that data, converting it and generating documentation for your API automatically.
11 |
12 | But there are situations where you might need to access the `Request` object directly.
13 |
14 | ## Details about the `Request` object
15 |
16 | As **FastAPI** is actually **Starlette** underneath, with a layer of several tools on top, you can use Starlette's `Request` object directly when you need to.
17 |
18 | It would also mean that if you get data from the `Request` object directly (for example, read the body) it won't be validated, converted or documented (with OpenAPI, for the automatic API user interface) by FastAPI.
19 |
20 | Although any other parameter declared normally (for example, the body with a Pydantic model) would still be validated, converted, annotated, etc.
21 |
22 | But there are specific cases where it's useful to get the `Request` object.
23 |
24 | ## Use the `Request` object directly
25 |
26 | Let's imagine you want to get the client's IP address/host inside of your *path operation function*.
27 |
28 | For that you need to access the request directly.
29 |
30 | ```Python hl_lines="1 7 8"
31 | {!./src/using_request_directly/tutorial001.py!}
32 | ```
33 |
34 | By declaring a *path operation function* parameter with the type being the `Request` **FastAPI** will know to pass the `Request` in that parameter.
35 |
36 | !!! tip
37 | Note that in this case, we are declaring a path parameter beside the request parameter.
38 |
39 | So, the path parameter will be extracted, validated, converted to the specified type and annotated with OpenAPI.
40 |
41 | The same way, you can declare any other parameter as normally, and additionally, get the `Request` too.
42 |
43 | ## `Request` documentation
44 |
45 | You can read more details about the `Request` object in the official Starlette documentation site .
46 |
47 | !!! note "Technical Details"
48 | You could also use `from starlette.requests import Request`.
49 |
50 | **FastAPI** provides it directly just as a convenience for you, the developer. But it comes directly from Starlette.
51 |
--------------------------------------------------------------------------------
/advanced/wsgi.md:
--------------------------------------------------------------------------------
1 | You can mount WSGI applications as you saw with [Sub Applications - Behind a Proxy, Mounts](./sub-applications-proxy.md){.internal-link target=_blank}.
2 |
3 | For that, you can use the `WSGIMiddleware` and use it to wrap your WSGI application, for example, Flask, Django, etc.
4 |
5 | ## Using `WSGIMiddleware`
6 |
7 | You need to import `WSGIMiddleware`.
8 |
9 | Then wrap the WSGI (e.g. Flask) app with the middleware.
10 |
11 | And then mount that under a path.
12 |
13 | ```Python hl_lines="1 3 22"
14 | {!./src/wsgi/tutorial001.py!}
15 | ```
16 |
17 | ## Check it
18 |
19 | Now, every request under the path `/v1/` will be handled by the Flask application.
20 |
21 | And the rest will be handled by **FastAPI**.
22 |
23 | If you run it with Uvicorn and go to http://localhost:8000/v1/ you will see the response from Flask:
24 |
25 | ```txt
26 | Hello, World from Flask!
27 | ```
28 |
29 | And if you go to http://localhost:8000/v2 you will see the response from FastAPI:
30 |
31 | ```JSON
32 | {
33 | "message": "Hello World"
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/favicon.png
--------------------------------------------------------------------------------
/img/github-social-preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/github-social-preview.png
--------------------------------------------------------------------------------
/img/icon-transparent-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/icon-transparent-bg.png
--------------------------------------------------------------------------------
/img/icon-white-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/icon-white-bg.png
--------------------------------------------------------------------------------
/img/icon-white.svg:
--------------------------------------------------------------------------------
1 |
2 |
13 |
15 |
17 |
18 |
20 | image/svg+xml
21 |
23 |
24 |
25 |
26 |
27 |
30 |
34 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/img/index/index-01-swagger-ui-simple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/index/index-01-swagger-ui-simple.png
--------------------------------------------------------------------------------
/img/index/index-02-redoc-simple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/index/index-02-redoc-simple.png
--------------------------------------------------------------------------------
/img/index/index-03-swagger-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/index/index-03-swagger-02.png
--------------------------------------------------------------------------------
/img/index/index-04-swagger-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/index/index-04-swagger-03.png
--------------------------------------------------------------------------------
/img/index/index-05-swagger-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/index/index-05-swagger-04.png
--------------------------------------------------------------------------------
/img/index/index-06-redoc-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/index/index-06-redoc-02.png
--------------------------------------------------------------------------------
/img/logo-margin/logo-teal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/logo-margin/logo-teal.png
--------------------------------------------------------------------------------
/img/logo-margin/logo-teal.svg:
--------------------------------------------------------------------------------
1 |
2 |
13 |
15 |
17 |
18 |
20 | image/svg+xml
21 |
23 |
24 |
25 |
26 |
27 |
34 |
37 |
41 | FastAPI
51 |
52 |
53 |
--------------------------------------------------------------------------------
/img/logo-margin/logo-white-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/logo-margin/logo-white-bg.png
--------------------------------------------------------------------------------
/img/logo-teal.svg:
--------------------------------------------------------------------------------
1 |
2 |
13 |
15 |
17 |
18 |
20 | image/svg+xml
21 |
23 |
24 |
25 |
26 |
27 |
30 |
34 | FastAPI
44 |
45 |
46 |
--------------------------------------------------------------------------------
/img/pycharm-completion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/pycharm-completion.png
--------------------------------------------------------------------------------
/img/python-types/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/python-types/image01.png
--------------------------------------------------------------------------------
/img/python-types/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/python-types/image02.png
--------------------------------------------------------------------------------
/img/python-types/image03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/python-types/image03.png
--------------------------------------------------------------------------------
/img/python-types/image04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/python-types/image04.png
--------------------------------------------------------------------------------
/img/python-types/image05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/python-types/image05.png
--------------------------------------------------------------------------------
/img/python-types/image06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/python-types/image06.png
--------------------------------------------------------------------------------
/img/tutorial/additional-responses/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/additional-responses/image01.png
--------------------------------------------------------------------------------
/img/tutorial/application-configuration/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/application-configuration/image01.png
--------------------------------------------------------------------------------
/img/tutorial/async-sql-databases/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/async-sql-databases/image01.png
--------------------------------------------------------------------------------
/img/tutorial/bigger-applications/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/bigger-applications/image01.png
--------------------------------------------------------------------------------
/img/tutorial/body-fields/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/body-fields/image01.png
--------------------------------------------------------------------------------
/img/tutorial/body-nested-models/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/body-nested-models/image01.png
--------------------------------------------------------------------------------
/img/tutorial/body/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/body/image01.png
--------------------------------------------------------------------------------
/img/tutorial/body/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/body/image02.png
--------------------------------------------------------------------------------
/img/tutorial/body/image03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/body/image03.png
--------------------------------------------------------------------------------
/img/tutorial/body/image04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/body/image04.png
--------------------------------------------------------------------------------
/img/tutorial/body/image05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/body/image05.png
--------------------------------------------------------------------------------
/img/tutorial/custom-response/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/custom-response/image01.png
--------------------------------------------------------------------------------
/img/tutorial/debugging/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/debugging/image01.png
--------------------------------------------------------------------------------
/img/tutorial/dependencies/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/dependencies/image01.png
--------------------------------------------------------------------------------
/img/tutorial/dependencies/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/dependencies/image02.png
--------------------------------------------------------------------------------
/img/tutorial/extending-openapi/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/extending-openapi/image01.png
--------------------------------------------------------------------------------
/img/tutorial/graphql/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/graphql/image01.png
--------------------------------------------------------------------------------
/img/tutorial/openapi-callbacks/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/openapi-callbacks/image01.png
--------------------------------------------------------------------------------
/img/tutorial/path-operation-configuration/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/path-operation-configuration/image01.png
--------------------------------------------------------------------------------
/img/tutorial/path-operation-configuration/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/path-operation-configuration/image02.png
--------------------------------------------------------------------------------
/img/tutorial/path-operation-configuration/image03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/path-operation-configuration/image03.png
--------------------------------------------------------------------------------
/img/tutorial/path-operation-configuration/image04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/path-operation-configuration/image04.png
--------------------------------------------------------------------------------
/img/tutorial/path-operation-configuration/image05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/path-operation-configuration/image05.png
--------------------------------------------------------------------------------
/img/tutorial/path-params/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/path-params/image01.png
--------------------------------------------------------------------------------
/img/tutorial/path-params/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/path-params/image02.png
--------------------------------------------------------------------------------
/img/tutorial/path-params/image03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/path-params/image03.png
--------------------------------------------------------------------------------
/img/tutorial/query-params-str-validations/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/query-params-str-validations/image01.png
--------------------------------------------------------------------------------
/img/tutorial/query-params-str-validations/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/query-params-str-validations/image02.png
--------------------------------------------------------------------------------
/img/tutorial/response-model/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/response-model/image01.png
--------------------------------------------------------------------------------
/img/tutorial/response-model/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/response-model/image02.png
--------------------------------------------------------------------------------
/img/tutorial/response-status-code/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/response-status-code/image01.png
--------------------------------------------------------------------------------
/img/tutorial/response-status-code/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/response-status-code/image02.png
--------------------------------------------------------------------------------
/img/tutorial/security/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image01.png
--------------------------------------------------------------------------------
/img/tutorial/security/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image02.png
--------------------------------------------------------------------------------
/img/tutorial/security/image03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image03.png
--------------------------------------------------------------------------------
/img/tutorial/security/image04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image04.png
--------------------------------------------------------------------------------
/img/tutorial/security/image05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image05.png
--------------------------------------------------------------------------------
/img/tutorial/security/image06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image06.png
--------------------------------------------------------------------------------
/img/tutorial/security/image07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image07.png
--------------------------------------------------------------------------------
/img/tutorial/security/image08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image08.png
--------------------------------------------------------------------------------
/img/tutorial/security/image09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image09.png
--------------------------------------------------------------------------------
/img/tutorial/security/image10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image10.png
--------------------------------------------------------------------------------
/img/tutorial/security/image11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image11.png
--------------------------------------------------------------------------------
/img/tutorial/security/image12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/security/image12.png
--------------------------------------------------------------------------------
/img/tutorial/sql-databases/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/sql-databases/image01.png
--------------------------------------------------------------------------------
/img/tutorial/sql-databases/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/sql-databases/image02.png
--------------------------------------------------------------------------------
/img/tutorial/sub-applications/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/sub-applications/image01.png
--------------------------------------------------------------------------------
/img/tutorial/sub-applications/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/sub-applications/image02.png
--------------------------------------------------------------------------------
/img/tutorial/websockets/image01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/websockets/image01.png
--------------------------------------------------------------------------------
/img/tutorial/websockets/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/websockets/image02.png
--------------------------------------------------------------------------------
/img/tutorial/websockets/image03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/websockets/image03.png
--------------------------------------------------------------------------------
/img/tutorial/websockets/image04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/tutorial/websockets/image04.png
--------------------------------------------------------------------------------
/img/vscode-completion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/img/vscode-completion.png
--------------------------------------------------------------------------------
/src/additional_responses/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import JSONResponse
3 | from pydantic import BaseModel
4 |
5 |
6 | class Item(BaseModel):
7 | id: str
8 | value: str
9 |
10 |
11 | class Message(BaseModel):
12 | message: str
13 |
14 |
15 | app = FastAPI()
16 |
17 |
18 | @app.get("/items/{item_id}", response_model=Item, responses={404: {"model": Message}})
19 | async def read_item(item_id: str):
20 | if item_id == "foo":
21 | return {"id": "foo", "value": "there goes my hero"}
22 | else:
23 | return JSONResponse(status_code=404, content={"message": "Item not found"})
24 |
--------------------------------------------------------------------------------
/src/additional_responses/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import FileResponse
3 | from pydantic import BaseModel
4 |
5 |
6 | class Item(BaseModel):
7 | id: str
8 | value: str
9 |
10 |
11 | app = FastAPI()
12 |
13 |
14 | @app.get(
15 | "/items/{item_id}",
16 | response_model=Item,
17 | responses={
18 | 200: {
19 | "content": {"image/png": {}},
20 | "description": "Return the JSON item or an image.",
21 | }
22 | },
23 | )
24 | async def read_item(item_id: str, img: bool = None):
25 | if img:
26 | return FileResponse("image.png", media_type="image/png")
27 | else:
28 | return {"id": "foo", "value": "there goes my hero"}
29 |
--------------------------------------------------------------------------------
/src/additional_responses/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import JSONResponse
3 | from pydantic import BaseModel
4 |
5 |
6 | class Item(BaseModel):
7 | id: str
8 | value: str
9 |
10 |
11 | class Message(BaseModel):
12 | message: str
13 |
14 |
15 | app = FastAPI()
16 |
17 |
18 | @app.get(
19 | "/items/{item_id}",
20 | response_model=Item,
21 | responses={
22 | 404: {"model": Message, "description": "The item was not found"},
23 | 200: {
24 | "description": "Item requested by ID",
25 | "content": {
26 | "application/json": {
27 | "example": {"id": "bar", "value": "The bar tenders"}
28 | }
29 | },
30 | },
31 | },
32 | )
33 | async def read_item(item_id: str):
34 | if item_id == "foo":
35 | return {"id": "foo", "value": "there goes my hero"}
36 | else:
37 | return JSONResponse(status_code=404, content={"message": "Item not found"})
38 |
--------------------------------------------------------------------------------
/src/additional_responses/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import FileResponse
3 | from pydantic import BaseModel
4 |
5 |
6 | class Item(BaseModel):
7 | id: str
8 | value: str
9 |
10 |
11 | responses = {
12 | 404: {"description": "Item not found"},
13 | 302: {"description": "The item was moved"},
14 | 403: {"description": "Not enough privileges"},
15 | }
16 |
17 |
18 | app = FastAPI()
19 |
20 |
21 | @app.get(
22 | "/items/{item_id}",
23 | response_model=Item,
24 | responses={**responses, 200: {"content": {"image/png": {}}}},
25 | )
26 | async def read_item(item_id: str, img: bool = None):
27 | if img:
28 | return FileResponse("image.png", media_type="image/png")
29 | else:
30 | return {"id": "foo", "value": "there goes my hero"}
31 |
--------------------------------------------------------------------------------
/src/additional_status_codes/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import Body, FastAPI, status
2 | from fastapi.responses import JSONResponse
3 |
4 | app = FastAPI()
5 |
6 | items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
7 |
8 |
9 | @app.put("/items/{item_id}")
10 | async def upsert_item(item_id: str, name: str = Body(None), size: int = Body(None)):
11 | if item_id in items:
12 | item = items[item_id]
13 | item["name"] = name
14 | item["size"] = size
15 | return item
16 | else:
17 | item = {"name": name, "size": size}
18 | items[item_id] = item
19 | return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)
20 |
--------------------------------------------------------------------------------
/src/advanced_middleware/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
3 |
4 | app = FastAPI()
5 |
6 | app.add_middleware(HTTPSRedirectMiddleware)
7 |
8 |
9 | @app.get("/")
10 | async def main():
11 | return {"message": "Hello World"}
12 |
--------------------------------------------------------------------------------
/src/advanced_middleware/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.middleware.trustedhost import TrustedHostMiddleware
3 |
4 | app = FastAPI()
5 |
6 | app.add_middleware(
7 | TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"]
8 | )
9 |
10 |
11 | @app.get("/")
12 | async def main():
13 | return {"message": "Hello World"}
14 |
--------------------------------------------------------------------------------
/src/advanced_middleware/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.middleware.gzip import GZipMiddleware
3 |
4 | app = FastAPI()
5 |
6 | app.add_middleware(GZipMiddleware, minimum_size=1000)
7 |
8 |
9 | @app.get("/")
10 | async def main():
11 | return "somebigcontent"
12 |
--------------------------------------------------------------------------------
/src/app_testing/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/src/app_testing/__init__.py
--------------------------------------------------------------------------------
/src/app_testing/main.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/")
7 | async def read_main():
8 | return {"msg": "Hello World"}
9 |
--------------------------------------------------------------------------------
/src/app_testing/main_b.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Header, HTTPException
2 | from pydantic import BaseModel
3 |
4 | fake_secret_token = "coneofsilence"
5 |
6 | fake_db = {
7 | "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
8 | "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
9 | }
10 |
11 | app = FastAPI()
12 |
13 |
14 | class Item(BaseModel):
15 | id: str
16 | title: str
17 | description: str = None
18 |
19 |
20 | @app.get("/items/{item_id}", response_model=Item)
21 | async def read_main(item_id: str, x_token: str = Header(...)):
22 | if x_token != fake_secret_token:
23 | raise HTTPException(status_code=400, detail="Invalid X-Token header")
24 | if item_id not in fake_db:
25 | raise HTTPException(status_code=404, detail="Item not found")
26 | return fake_db[item_id]
27 |
28 |
29 | @app.post("/items/", response_model=Item)
30 | async def create_item(item: Item, x_token: str = Header(...)):
31 | if x_token != fake_secret_token:
32 | raise HTTPException(status_code=400, detail="Invalid X-Token header")
33 | if item.id in fake_db:
34 | raise HTTPException(status_code=400, detail="Item already exists")
35 | fake_db[item.id] = item
36 | return item
37 |
--------------------------------------------------------------------------------
/src/app_testing/test_main.py:
--------------------------------------------------------------------------------
1 | from fastapi.testclient import TestClient
2 |
3 | from .main import app
4 |
5 | client = TestClient(app)
6 |
7 |
8 | def test_read_main():
9 | response = client.get("/")
10 | assert response.status_code == 200
11 | assert response.json() == {"msg": "Hello World"}
12 |
--------------------------------------------------------------------------------
/src/app_testing/test_main_b.py:
--------------------------------------------------------------------------------
1 | from fastapi.testclient import TestClient
2 |
3 | from .main_b import app
4 |
5 | client = TestClient(app)
6 |
7 |
8 | def test_read_item():
9 | response = client.get("/items/foo", headers={"X-Token": "coneofsilence"})
10 | assert response.status_code == 200
11 | assert response.json() == {
12 | "id": "foo",
13 | "title": "Foo",
14 | "description": "There goes my hero",
15 | }
16 |
17 |
18 | def test_read_item_bad_token():
19 | response = client.get("/items/foo", headers={"X-Token": "hailhydra"})
20 | assert response.status_code == 400
21 | assert response.json() == {"detail": "Invalid X-Token header"}
22 |
23 |
24 | def test_read_inexistent_item():
25 | response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
26 | assert response.status_code == 404
27 | assert response.json() == {"detail": "Item not found"}
28 |
29 |
30 | def test_create_item():
31 | response = client.post(
32 | "/items/",
33 | headers={"X-Token": "coneofsilence"},
34 | json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
35 | )
36 | assert response.status_code == 200
37 | assert response.json() == {
38 | "id": "foobar",
39 | "title": "Foo Bar",
40 | "description": "The Foo Barters",
41 | }
42 |
43 |
44 | def test_create_item_bad_token():
45 | response = client.post(
46 | "/items/",
47 | headers={"X-Token": "hailhydra"},
48 | json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"},
49 | )
50 | assert response.status_code == 400
51 | assert response.json() == {"detail": "Invalid X-Token header"}
52 |
53 |
54 | def test_create_existing_token():
55 | response = client.post(
56 | "/items/",
57 | headers={"X-Token": "coneofsilence"},
58 | json={
59 | "id": "foo",
60 | "title": "The Foo ID Stealers",
61 | "description": "There goes my stealer",
62 | },
63 | )
64 | assert response.status_code == 400
65 | assert response.json() == {"detail": "Item already exists"}
66 |
--------------------------------------------------------------------------------
/src/app_testing/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.testclient import TestClient
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/")
8 | async def read_main():
9 | return {"msg": "Hello World"}
10 |
11 |
12 | client = TestClient(app)
13 |
14 |
15 | def test_read_main():
16 | response = client.get("/")
17 | assert response.status_code == 200
18 | assert response.json() == {"msg": "Hello World"}
19 |
--------------------------------------------------------------------------------
/src/app_testing/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.testclient import TestClient
3 | from fastapi.websockets import WebSocket
4 |
5 | app = FastAPI()
6 |
7 |
8 | @app.get("/")
9 | async def read_main():
10 | return {"msg": "Hello World"}
11 |
12 |
13 | @app.websocket_route("/ws")
14 | async def websocket(websocket: WebSocket):
15 | await websocket.accept()
16 | await websocket.send_json({"msg": "Hello WebSocket"})
17 | await websocket.close()
18 |
19 |
20 | def test_read_main():
21 | client = TestClient(app)
22 | response = client.get("/")
23 | assert response.status_code == 200
24 | assert response.json() == {"msg": "Hello World"}
25 |
26 |
27 | def test_websocket():
28 | client = TestClient(app)
29 | with client.websocket_connect("/ws") as websocket:
30 | data = websocket.receive_json()
31 | assert data == {"msg": "Hello WebSocket"}
32 |
--------------------------------------------------------------------------------
/src/app_testing/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.testclient import TestClient
3 |
4 | app = FastAPI()
5 |
6 | items = {}
7 |
8 |
9 | @app.on_event("startup")
10 | async def startup_event():
11 | items["foo"] = {"name": "Fighters"}
12 | items["bar"] = {"name": "Tenders"}
13 |
14 |
15 | @app.get("/items/{item_id}")
16 | async def read_items(item_id: str):
17 | return items[item_id]
18 |
19 |
20 | def test_read_items():
21 | with TestClient(app) as client:
22 | response = client.get("/items/foo")
23 | assert response.status_code == 200
24 | assert response.json() == {"name": "Fighters"}
25 |
--------------------------------------------------------------------------------
/src/application_configuration/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI(
4 | title="My Super Project",
5 | description="This is a very fancy project, with auto docs for the API and everything",
6 | version="2.5.0",
7 | )
8 |
9 |
10 | @app.get("/items/")
11 | async def read_items():
12 | return [{"name": "Foo"}]
13 |
--------------------------------------------------------------------------------
/src/application_configuration/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI(openapi_url="/api/v1/openapi.json")
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items():
8 | return [{"name": "Foo"}]
9 |
--------------------------------------------------------------------------------
/src/application_configuration/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI(docs_url="/documentation", redoc_url=None)
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items():
8 | return [{"name": "Foo"}]
9 |
--------------------------------------------------------------------------------
/src/async_sql_databases/tutorial001.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | import databases
4 | import sqlalchemy
5 | from fastapi import FastAPI
6 | from pydantic import BaseModel
7 |
8 | # SQLAlchemy specific code, as with any other app
9 | DATABASE_URL = "sqlite:///./test.db"
10 | # DATABASE_URL = "postgresql://user:password@postgresserver/db"
11 |
12 | database = databases.Database(DATABASE_URL)
13 |
14 | metadata = sqlalchemy.MetaData()
15 |
16 | notes = sqlalchemy.Table(
17 | "notes",
18 | metadata,
19 | sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True),
20 | sqlalchemy.Column("text", sqlalchemy.String),
21 | sqlalchemy.Column("completed", sqlalchemy.Boolean),
22 | )
23 |
24 |
25 | engine = sqlalchemy.create_engine(
26 | DATABASE_URL, connect_args={"check_same_thread": False}
27 | )
28 | metadata.create_all(engine)
29 |
30 |
31 | class NoteIn(BaseModel):
32 | text: str
33 | completed: bool
34 |
35 |
36 | class Note(BaseModel):
37 | id: int
38 | text: str
39 | completed: bool
40 |
41 |
42 | app = FastAPI()
43 |
44 |
45 | @app.on_event("startup")
46 | async def startup():
47 | await database.connect()
48 |
49 |
50 | @app.on_event("shutdown")
51 | async def shutdown():
52 | await database.disconnect()
53 |
54 |
55 | @app.get("/notes/", response_model=List[Note])
56 | async def read_notes():
57 | query = notes.select()
58 | return await database.fetch_all(query)
59 |
60 |
61 | @app.post("/notes/", response_model=Note)
62 | async def create_note(note: NoteIn):
63 | query = notes.insert().values(text=note.text, completed=note.completed)
64 | last_record_id = await database.execute(query)
65 | return {**note.dict(), "id": last_record_id}
66 |
--------------------------------------------------------------------------------
/src/background_tasks/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import BackgroundTasks, FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | def write_notification(email: str, message=""):
7 | with open("log.txt", mode="w") as email_file:
8 | content = f"notification for {email}: {message}"
9 | email_file.write(content)
10 |
11 |
12 | @app.post("/send-notification/{email}")
13 | async def send_notification(email: str, background_tasks: BackgroundTasks):
14 | background_tasks.add_task(write_notification, email, message="some notification")
15 | return {"message": "Notification sent in the background"}
16 |
--------------------------------------------------------------------------------
/src/background_tasks/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import BackgroundTasks, Depends, FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | def write_log(message: str):
7 | with open("log.txt", mode="a") as log:
8 | log.write(message)
9 |
10 |
11 | def get_query(background_tasks: BackgroundTasks, q: str = None):
12 | if q:
13 | message = f"found query: {q}\n"
14 | background_tasks.add_task(write_log, message)
15 | return q
16 |
17 |
18 | @app.post("/send-notification/{email}")
19 | async def send_notification(
20 | email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query)
21 | ):
22 | message = f"message to {email}\n"
23 | background_tasks.add_task(write_log, message)
24 | return {"message": "Message sent"}
25 |
--------------------------------------------------------------------------------
/src/bigger_applications/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/src/bigger_applications/__init__.py
--------------------------------------------------------------------------------
/src/bigger_applications/app/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/src/bigger_applications/app/__init__.py
--------------------------------------------------------------------------------
/src/bigger_applications/app/main.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI, Header, HTTPException
2 |
3 | from .routers import items, users
4 |
5 | app = FastAPI()
6 |
7 |
8 | async def get_token_header(x_token: str = Header(...)):
9 | if x_token != "fake-super-secret-token":
10 | raise HTTPException(status_code=400, detail="X-Token header invalid")
11 |
12 |
13 | app.include_router(users.router)
14 | app.include_router(
15 | items.router,
16 | prefix="/items",
17 | tags=["items"],
18 | dependencies=[Depends(get_token_header)],
19 | responses={404: {"description": "Not found"}},
20 | )
21 |
--------------------------------------------------------------------------------
/src/bigger_applications/app/routers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/src/bigger_applications/app/routers/__init__.py
--------------------------------------------------------------------------------
/src/bigger_applications/app/routers/items.py:
--------------------------------------------------------------------------------
1 | from fastapi import APIRouter, HTTPException
2 |
3 | router = APIRouter()
4 |
5 |
6 | @router.get("/")
7 | async def read_items():
8 | return [{"name": "Item Foo"}, {"name": "item Bar"}]
9 |
10 |
11 | @router.get("/{item_id}")
12 | async def read_item(item_id: str):
13 | return {"name": "Fake Specific Item", "item_id": item_id}
14 |
15 |
16 | @router.put(
17 | "/{item_id}",
18 | tags=["custom"],
19 | responses={403: {"description": "Operation forbidden"}},
20 | )
21 | async def update_item(item_id: str):
22 | if item_id != "foo":
23 | raise HTTPException(status_code=403, detail="You can only update the item: foo")
24 | return {"item_id": item_id, "name": "The Fighters"}
25 |
--------------------------------------------------------------------------------
/src/bigger_applications/app/routers/users.py:
--------------------------------------------------------------------------------
1 | from fastapi import APIRouter
2 |
3 | router = APIRouter()
4 |
5 |
6 | @router.get("/users/", tags=["users"])
7 | async def read_users():
8 | return [{"username": "Foo"}, {"username": "Bar"}]
9 |
10 |
11 | @router.get("/users/me", tags=["users"])
12 | async def read_user_me():
13 | return {"username": "fakecurrentuser"}
14 |
15 |
16 | @router.get("/users/{username}", tags=["users"])
17 | async def read_user(username: str):
18 | return {"username": username}
19 |
--------------------------------------------------------------------------------
/src/body/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel
3 |
4 |
5 | class Item(BaseModel):
6 | name: str
7 | description: str = None
8 | price: float
9 | tax: float = None
10 |
11 |
12 | app = FastAPI()
13 |
14 |
15 | @app.post("/items/")
16 | async def create_item(item: Item):
17 | return item
18 |
--------------------------------------------------------------------------------
/src/body/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel
3 |
4 |
5 | class Item(BaseModel):
6 | name: str
7 | description: str = None
8 | price: float
9 | tax: float = None
10 |
11 |
12 | app = FastAPI()
13 |
14 |
15 | @app.post("/items/")
16 | async def create_item(item: Item):
17 | item_dict = item.dict()
18 | if item.tax:
19 | price_with_tax = item.price + item.tax
20 | item_dict.update({"price_with_tax": price_with_tax})
21 | return item_dict
22 |
--------------------------------------------------------------------------------
/src/body/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel
3 |
4 |
5 | class Item(BaseModel):
6 | name: str
7 | description: str = None
8 | price: float
9 | tax: float = None
10 |
11 |
12 | app = FastAPI()
13 |
14 |
15 | @app.put("/items/{item_id}")
16 | async def create_item(item_id: int, item: Item):
17 | return {"item_id": item_id, **item.dict()}
18 |
--------------------------------------------------------------------------------
/src/body/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel
3 |
4 |
5 | class Item(BaseModel):
6 | name: str
7 | description: str = None
8 | price: float
9 | tax: float = None
10 |
11 |
12 | app = FastAPI()
13 |
14 |
15 | @app.put("/items/{item_id}")
16 | async def create_item(item_id: int, item: Item, q: str = None):
17 | result = {"item_id": item_id, **item.dict()}
18 | if q:
19 | result.update({"q": q})
20 | return result
21 |
--------------------------------------------------------------------------------
/src/body_fields/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import Body, FastAPI
2 | from pydantic import BaseModel, Field
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = Field(None, title="The description of the item", max_length=300)
10 | price: float = Field(..., gt=0, description="The price must be greater than zero")
11 | tax: float = None
12 |
13 |
14 | @app.put("/items/{item_id}")
15 | async def update_item(*, item_id: int, item: Item = Body(..., embed=True)):
16 | results = {"item_id": item_id, "item": item}
17 | return results
18 |
--------------------------------------------------------------------------------
/src/body_fields/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import Body, FastAPI
2 | from pydantic import BaseModel
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = None
10 | price: float
11 | tax: float = None
12 |
13 |
14 | @app.put("/items/{item_id}")
15 | async def update_item(
16 | *,
17 | item_id: int,
18 | item: Item = Body(
19 | ...,
20 | example={
21 | "name": "Foo",
22 | "description": "A very nice Item",
23 | "price": 35.4,
24 | "tax": 3.2,
25 | },
26 | )
27 | ):
28 | results = {"item_id": item_id, "item": item}
29 | return results
30 |
--------------------------------------------------------------------------------
/src/body_multiple_params/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Path
2 | from pydantic import BaseModel
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = None
10 | price: float
11 | tax: float = None
12 |
13 |
14 | @app.put("/items/{item_id}")
15 | async def update_item(
16 | *,
17 | item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
18 | q: str = None,
19 | item: Item = None,
20 | ):
21 | results = {"item_id": item_id}
22 | if q:
23 | results.update({"q": q})
24 | if item:
25 | results.update({"item": item})
26 | return results
27 |
--------------------------------------------------------------------------------
/src/body_multiple_params/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = None
10 | price: float
11 | tax: float = None
12 |
13 |
14 | class User(BaseModel):
15 | username: str
16 | full_name: str = None
17 |
18 |
19 | @app.put("/items/{item_id}")
20 | async def update_item(*, item_id: int, item: Item, user: User):
21 | results = {"item_id": item_id, "item": item, "user": user}
22 | return results
23 |
--------------------------------------------------------------------------------
/src/body_multiple_params/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import Body, FastAPI
2 | from pydantic import BaseModel
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = None
10 | price: float
11 | tax: float = None
12 |
13 |
14 | class User(BaseModel):
15 | username: str
16 | full_name: str = None
17 |
18 |
19 | @app.put("/items/{item_id}")
20 | async def update_item(
21 | *, item_id: int, item: Item, user: User, importance: int = Body(...)
22 | ):
23 | results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
24 | return results
25 |
--------------------------------------------------------------------------------
/src/body_multiple_params/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import Body, FastAPI
2 | from pydantic import BaseModel
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = None
10 | price: float
11 | tax: float = None
12 |
13 |
14 | class User(BaseModel):
15 | username: str
16 | full_name: str = None
17 |
18 |
19 | @app.put("/items/{item_id}")
20 | async def update_item(
21 | *,
22 | item_id: int,
23 | item: Item,
24 | user: User,
25 | importance: int = Body(..., gt=0),
26 | q: str = None
27 | ):
28 | results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
29 | if q:
30 | results.update({"q": q})
31 | return results
32 |
--------------------------------------------------------------------------------
/src/body_multiple_params/tutorial005.py:
--------------------------------------------------------------------------------
1 | from fastapi import Body, FastAPI
2 | from pydantic import BaseModel
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = None
10 | price: float
11 | tax: float = None
12 |
13 |
14 | @app.put("/items/{item_id}")
15 | async def update_item(*, item_id: int, item: Item = Body(..., embed=True)):
16 | results = {"item_id": item_id, "item": item}
17 | return results
18 |
--------------------------------------------------------------------------------
/src/body_nested_models/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = None
10 | price: float
11 | tax: float = None
12 | tags: list = []
13 |
14 |
15 | @app.put("/items/{item_id}")
16 | async def update_item(*, item_id: int, item: Item):
17 | results = {"item_id": item_id, "item": item}
18 | return results
19 |
--------------------------------------------------------------------------------
/src/body_nested_models/tutorial002.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = None
14 | tags: List[str] = []
15 |
16 |
17 | @app.put("/items/{item_id}")
18 | async def update_item(*, item_id: int, item: Item):
19 | results = {"item_id": item_id, "item": item}
20 | return results
21 |
--------------------------------------------------------------------------------
/src/body_nested_models/tutorial003.py:
--------------------------------------------------------------------------------
1 | from typing import Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = None
14 | tags: Set[str] = set()
15 |
16 |
17 | @app.put("/items/{item_id}")
18 | async def update_item(*, item_id: int, item: Item):
19 | results = {"item_id": item_id, "item": item}
20 | return results
21 |
--------------------------------------------------------------------------------
/src/body_nested_models/tutorial004.py:
--------------------------------------------------------------------------------
1 | from typing import Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Image(BaseModel):
10 | url: str
11 | name: str
12 |
13 |
14 | class Item(BaseModel):
15 | name: str
16 | description: str = None
17 | price: float
18 | tax: float = None
19 | tags: Set[str] = []
20 | image: Image = None
21 |
22 |
23 | @app.put("/items/{item_id}")
24 | async def update_item(*, item_id: int, item: Item):
25 | results = {"item_id": item_id, "item": item}
26 | return results
27 |
--------------------------------------------------------------------------------
/src/body_nested_models/tutorial005.py:
--------------------------------------------------------------------------------
1 | from typing import Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel, HttpUrl
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Image(BaseModel):
10 | url: HttpUrl
11 | name: str
12 |
13 |
14 | class Item(BaseModel):
15 | name: str
16 | description: str = None
17 | price: float
18 | tax: float = None
19 | tags: Set[str] = []
20 | image: Image = None
21 |
22 |
23 | @app.put("/items/{item_id}")
24 | async def update_item(*, item_id: int, item: Item):
25 | results = {"item_id": item_id, "item": item}
26 | return results
27 |
--------------------------------------------------------------------------------
/src/body_nested_models/tutorial006.py:
--------------------------------------------------------------------------------
1 | from typing import List, Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel, HttpUrl
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Image(BaseModel):
10 | url: HttpUrl
11 | name: str
12 |
13 |
14 | class Item(BaseModel):
15 | name: str
16 | description: str = None
17 | price: float
18 | tax: float = None
19 | tags: Set[str] = []
20 | images: List[Image] = None
21 |
22 |
23 | @app.put("/items/{item_id}")
24 | async def update_item(*, item_id: int, item: Item):
25 | results = {"item_id": item_id, "item": item}
26 | return results
27 |
--------------------------------------------------------------------------------
/src/body_nested_models/tutorial007.py:
--------------------------------------------------------------------------------
1 | from typing import List, Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel, HttpUrl
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Image(BaseModel):
10 | url: HttpUrl
11 | name: str
12 |
13 |
14 | class Item(BaseModel):
15 | name: str
16 | description: str = None
17 | price: float
18 | tax: float = None
19 | tags: Set[str] = []
20 | images: List[Image] = None
21 |
22 |
23 | class Offer(BaseModel):
24 | name: str
25 | description: str = None
26 | price: float
27 | items: List[Item]
28 |
29 |
30 | @app.post("/offers/")
31 | async def create_offer(*, offer: Offer):
32 | return offer
33 |
--------------------------------------------------------------------------------
/src/body_nested_models/tutorial008.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel, HttpUrl
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Image(BaseModel):
10 | url: HttpUrl
11 | name: str
12 |
13 |
14 | @app.post("/images/multiple/")
15 | async def create_multiple_images(*, images: List[Image]):
16 | return images
17 |
--------------------------------------------------------------------------------
/src/body_nested_models/tutorial009.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 | from fastapi import FastAPI
4 |
5 | app = FastAPI()
6 |
7 |
8 | @app.post("/index-weights/")
9 | async def create_index_weights(weights: Dict[int, float]):
10 | return weights
11 |
--------------------------------------------------------------------------------
/src/body_updates/tutorial001.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI
4 | from fastapi.encoders import jsonable_encoder
5 | from pydantic import BaseModel
6 |
7 | app = FastAPI()
8 |
9 |
10 | class Item(BaseModel):
11 | name: str = None
12 | description: str = None
13 | price: float = None
14 | tax: float = 10.5
15 | tags: List[str] = []
16 |
17 |
18 | items = {
19 | "foo": {"name": "Foo", "price": 50.2},
20 | "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
21 | "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
22 | }
23 |
24 |
25 | @app.get("/items/{item_id}", response_model=Item)
26 | async def read_item(item_id: str):
27 | return items[item_id]
28 |
29 |
30 | @app.put("/items/{item_id}", response_model=Item)
31 | async def update_item(item_id: str, item: Item):
32 | update_item_encoded = jsonable_encoder(item)
33 | items[item_id] = update_item_encoded
34 | return update_item_encoded
35 |
--------------------------------------------------------------------------------
/src/body_updates/tutorial002.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI
4 | from fastapi.encoders import jsonable_encoder
5 | from pydantic import BaseModel
6 |
7 | app = FastAPI()
8 |
9 |
10 | class Item(BaseModel):
11 | name: str = None
12 | description: str = None
13 | price: float = None
14 | tax: float = 10.5
15 | tags: List[str] = []
16 |
17 |
18 | items = {
19 | "foo": {"name": "Foo", "price": 50.2},
20 | "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
21 | "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
22 | }
23 |
24 |
25 | @app.get("/items/{item_id}", response_model=Item)
26 | async def read_item(item_id: str):
27 | return items[item_id]
28 |
29 |
30 | @app.patch("/items/{item_id}", response_model=Item)
31 | async def update_item(item_id: str, item: Item):
32 | stored_item_data = items[item_id]
33 | stored_item_model = Item(**stored_item_data)
34 | update_data = item.dict(exclude_unset=True)
35 | updated_item = stored_item_model.copy(update=update_data)
36 | items[item_id] = jsonable_encoder(updated_item)
37 | return updated_item
38 |
--------------------------------------------------------------------------------
/src/cookie_params/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import Cookie, FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(*, ads_id: str = Cookie(None)):
8 | return {"ads_id": ads_id}
9 |
--------------------------------------------------------------------------------
/src/cors/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.middleware.cors import CORSMiddleware
3 |
4 | app = FastAPI()
5 |
6 | origins = [
7 | "http://localhost.tiangolo.com",
8 | "https://localhost.tiangolo.com",
9 | "http://localhost",
10 | "http://localhost:8080",
11 | ]
12 |
13 | app.add_middleware(
14 | CORSMiddleware,
15 | allow_origins=origins,
16 | allow_credentials=True,
17 | allow_methods=["*"],
18 | allow_headers=["*"],
19 | )
20 |
21 |
22 | @app.get("/")
23 | async def main():
24 | return {"message": "Hello World"}
25 |
--------------------------------------------------------------------------------
/src/custom_request_and_route/tutorial001.py:
--------------------------------------------------------------------------------
1 | import gzip
2 | from typing import Callable, List
3 |
4 | from fastapi import Body, FastAPI, Request, Response
5 | from fastapi.routing import APIRoute
6 |
7 |
8 | class GzipRequest(Request):
9 | async def body(self) -> bytes:
10 | if not hasattr(self, "_body"):
11 | body = await super().body()
12 | if "gzip" in self.headers.getlist("Content-Encoding"):
13 | body = gzip.decompress(body)
14 | self._body = body
15 | return self._body
16 |
17 |
18 | class GzipRoute(APIRoute):
19 | def get_route_handler(self) -> Callable:
20 | original_route_handler = super().get_route_handler()
21 |
22 | async def custom_route_handler(request: Request) -> Response:
23 | request = GzipRequest(request.scope, request.receive)
24 | return await original_route_handler(request)
25 |
26 | return custom_route_handler
27 |
28 |
29 | app = FastAPI()
30 | app.router.route_class = GzipRoute
31 |
32 |
33 | @app.post("/sum")
34 | async def sum_numbers(numbers: List[int] = Body(...)):
35 | return {"sum": sum(numbers)}
36 |
--------------------------------------------------------------------------------
/src/custom_request_and_route/tutorial002.py:
--------------------------------------------------------------------------------
1 | from typing import Callable, List
2 |
3 | from fastapi import Body, FastAPI, HTTPException, Request, Response
4 | from fastapi.exceptions import RequestValidationError
5 | from fastapi.routing import APIRoute
6 |
7 |
8 | class ValidationErrorLoggingRoute(APIRoute):
9 | def get_route_handler(self) -> Callable:
10 | original_route_handler = super().get_route_handler()
11 |
12 | async def custom_route_handler(request: Request) -> Response:
13 | try:
14 | return await original_route_handler(request)
15 | except RequestValidationError as exc:
16 | body = await request.body()
17 | detail = {"errors": exc.errors(), "body": body.decode()}
18 | raise HTTPException(status_code=422, detail=detail)
19 |
20 | return custom_route_handler
21 |
22 |
23 | app = FastAPI()
24 | app.router.route_class = ValidationErrorLoggingRoute
25 |
26 |
27 | @app.post("/")
28 | async def sum_numbers(numbers: List[int] = Body(...)):
29 | return sum(numbers)
30 |
--------------------------------------------------------------------------------
/src/custom_request_and_route/tutorial003.py:
--------------------------------------------------------------------------------
1 | import time
2 | from typing import Callable
3 |
4 | from fastapi import APIRouter, FastAPI, Request, Response
5 | from fastapi.routing import APIRoute
6 |
7 |
8 | class TimedRoute(APIRoute):
9 | def get_route_handler(self) -> Callable:
10 | original_route_handler = super().get_route_handler()
11 |
12 | async def custom_route_handler(request: Request) -> Response:
13 | before = time.time()
14 | response: Response = await original_route_handler(request)
15 | duration = time.time() - before
16 | response.headers["X-Response-Time"] = str(duration)
17 | print(f"route duration: {duration}")
18 | print(f"route response: {response}")
19 | print(f"route response headers: {response.headers}")
20 | return response
21 |
22 | return custom_route_handler
23 |
24 |
25 | app = FastAPI()
26 | router = APIRouter(route_class=TimedRoute)
27 |
28 |
29 | @app.get("/")
30 | async def not_timed():
31 | return {"message": "Not timed"}
32 |
33 |
34 | @router.get("/timed")
35 | async def timed():
36 | return {"message": "It's the time of my life"}
37 |
38 |
39 | app.include_router(router)
40 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import UJSONResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/items/", response_class=UJSONResponse)
8 | async def read_items():
9 | return [{"item_id": "Foo"}]
10 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial001b.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import ORJSONResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/items/", response_class=ORJSONResponse)
8 | async def read_items():
9 | return [{"item_id": "Foo"}]
10 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import HTMLResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/items/", response_class=HTMLResponse)
8 | async def read_items():
9 | return """
10 |
11 |
12 | Some HTML in here
13 |
14 |
15 | Look ma! HTML!
16 |
17 |
18 | """
19 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import HTMLResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/items/")
8 | async def read_items():
9 | html_content = """
10 |
11 |
12 | Some HTML in here
13 |
14 |
15 | Look ma! HTML!
16 |
17 |
18 | """
19 | return HTMLResponse(content=html_content, status_code=200)
20 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import HTMLResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | def generate_html_response():
8 | html_content = """
9 |
10 |
11 | Some HTML in here
12 |
13 |
14 | Look ma! HTML!
15 |
16 |
17 | """
18 | return HTMLResponse(content=html_content, status_code=200)
19 |
20 |
21 | @app.get("/items/", response_class=HTMLResponse)
22 | async def read_items():
23 | return generate_html_response()
24 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial005.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import PlainTextResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/", response_class=PlainTextResponse)
8 | async def main():
9 | return "Hello World"
10 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial006.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import RedirectResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/typer")
8 | async def read_typer():
9 | return RedirectResponse("https://typer.tiangolo.com")
10 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial007.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import StreamingResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | async def fake_video_streamer():
8 | for i in range(10):
9 | yield b"some fake video bytes"
10 |
11 |
12 | @app.get("/")
13 | async def main():
14 | return StreamingResponse(fake_video_streamer())
15 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial008.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import StreamingResponse
3 |
4 | some_file_path = "large-video-file.mp4"
5 | app = FastAPI()
6 |
7 |
8 | @app.get("/")
9 | def main():
10 | file_like = open(some_file_path, mode="rb")
11 | return StreamingResponse(file_like, media_type="video/mp4")
12 |
--------------------------------------------------------------------------------
/src/custom_response/tutorial009.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import FileResponse
3 |
4 | some_file_path = "large-video-file.mp4"
5 | app = FastAPI()
6 |
7 |
8 | @app.get("/")
9 | async def main():
10 | return FileResponse(some_file_path)
11 |
--------------------------------------------------------------------------------
/src/debugging/tutorial001.py:
--------------------------------------------------------------------------------
1 | import uvicorn
2 | from fastapi import FastAPI
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/")
8 | def root():
9 | a = "a"
10 | b = "b" + a
11 | return {"hello world": b}
12 |
13 |
14 | if __name__ == "__main__":
15 | uvicorn.run(app, host="0.0.0.0", port=8000)
16 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
7 | return {"q": q, "skip": skip, "limit": limit}
8 |
9 |
10 | @app.get("/items/")
11 | async def read_items(commons: dict = Depends(common_parameters)):
12 | return commons
13 |
14 |
15 | @app.get("/users/")
16 | async def read_users(commons: dict = Depends(common_parameters)):
17 | return commons
18 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
7 |
8 |
9 | class CommonQueryParams:
10 | def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
11 | self.q = q
12 | self.skip = skip
13 | self.limit = limit
14 |
15 |
16 | @app.get("/items/")
17 | async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
18 | response = {}
19 | if commons.q:
20 | response.update({"q": commons.q})
21 | items = fake_items_db[commons.skip : commons.skip + commons.limit]
22 | response.update({"items": items})
23 | return response
24 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
7 |
8 |
9 | class CommonQueryParams:
10 | def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
11 | self.q = q
12 | self.skip = skip
13 | self.limit = limit
14 |
15 |
16 | @app.get("/items/")
17 | async def read_items(commons=Depends(CommonQueryParams)):
18 | response = {}
19 | if commons.q:
20 | response.update({"q": commons.q})
21 | items = fake_items_db[commons.skip : commons.skip + commons.limit]
22 | response.update({"items": items})
23 | return response
24 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
7 |
8 |
9 | class CommonQueryParams:
10 | def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
11 | self.q = q
12 | self.skip = skip
13 | self.limit = limit
14 |
15 |
16 | @app.get("/items/")
17 | async def read_items(commons: CommonQueryParams = Depends()):
18 | response = {}
19 | if commons.q:
20 | response.update({"q": commons.q})
21 | items = fake_items_db[commons.skip : commons.skip + commons.limit]
22 | response.update({"items": items})
23 | return response
24 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial005.py:
--------------------------------------------------------------------------------
1 | from fastapi import Cookie, Depends, FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | def query_extractor(q: str = None):
7 | return q
8 |
9 |
10 | def query_or_cookie_extractor(
11 | q: str = Depends(query_extractor), last_query: str = Cookie(None)
12 | ):
13 | if not q:
14 | return last_query
15 | return q
16 |
17 |
18 | @app.get("/items/")
19 | async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
20 | return {"q_or_cookie": query_or_default}
21 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial006.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI, Header, HTTPException
2 |
3 | app = FastAPI()
4 |
5 |
6 | async def verify_token(x_token: str = Header(...)):
7 | if x_token != "fake-super-secret-token":
8 | raise HTTPException(status_code=400, detail="X-Token header invalid")
9 |
10 |
11 | async def verify_key(x_key: str = Header(...)):
12 | if x_key != "fake-super-secret-key":
13 | raise HTTPException(status_code=400, detail="X-Key header invalid")
14 | return x_key
15 |
16 |
17 | @app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)])
18 | async def read_items():
19 | return [{"item": "Foo"}, {"item": "Bar"}]
20 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial007.py:
--------------------------------------------------------------------------------
1 | async def get_db():
2 | db = DBSession()
3 | try:
4 | yield db
5 | finally:
6 | db.close()
7 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial008.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends
2 |
3 |
4 | async def dependency_a():
5 | dep_a = generate_dep_a()
6 | try:
7 | yield dep_a
8 | finally:
9 | dep_a.close()
10 |
11 |
12 | async def dependency_b(dep_a=Depends(dependency_a)):
13 | dep_b = generate_dep_b()
14 | try:
15 | yield dep_b
16 | finally:
17 | dep_b.close(dep_a)
18 |
19 |
20 | async def dependency_c(dep_b=Depends(dependency_b)):
21 | dep_c = generate_dep_c()
22 | try:
23 | yield dep_c
24 | finally:
25 | dep_c.close(dep_b)
26 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial009.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends
2 |
3 |
4 | async def dependency_a():
5 | dep_a = generate_dep_a()
6 | try:
7 | yield dep_a
8 | finally:
9 | dep_a.close()
10 |
11 |
12 | async def dependency_b(dep_a=Depends(dependency_a)):
13 | dep_b = generate_dep_b()
14 | try:
15 | yield dep_b
16 | finally:
17 | dep_b.close(dep_a)
18 |
19 |
20 | async def dependency_c(dep_b=Depends(dependency_b)):
21 | dep_c = generate_dep_c()
22 | try:
23 | yield dep_c
24 | finally:
25 | dep_c.close(dep_b)
26 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial010.py:
--------------------------------------------------------------------------------
1 | class MySuperContextManager:
2 | def __init__(self):
3 | self.db = DBSession()
4 |
5 | def __enter__(self):
6 | return self.db
7 |
8 | def __exit__(self, exc_type, exc_value, traceback):
9 | self.db.close()
10 |
11 |
12 | async def get_db():
13 | with MySuperContextManager() as db:
14 | yield db
15 |
--------------------------------------------------------------------------------
/src/dependencies/tutorial011.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | class FixedContentQueryChecker:
7 | def __init__(self, fixed_content: str):
8 | self.fixed_content = fixed_content
9 |
10 | def __call__(self, q: str = ""):
11 | if q:
12 | return self.fixed_content in q
13 | return False
14 |
15 |
16 | checker = FixedContentQueryChecker("bar")
17 |
18 |
19 | @app.get("/query-checker/")
20 | async def read_query_check(fixed_content_included: bool = Depends(checker)):
21 | return {"fixed_content_in_query": fixed_content_included}
22 |
--------------------------------------------------------------------------------
/src/dependency_testing/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI
2 | from fastapi.testclient import TestClient
3 |
4 | app = FastAPI()
5 |
6 |
7 | async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
8 | return {"q": q, "skip": skip, "limit": limit}
9 |
10 |
11 | @app.get("/items/")
12 | async def read_items(commons: dict = Depends(common_parameters)):
13 | return {"message": "Hello Items!", "params": commons}
14 |
15 |
16 | @app.get("/users/")
17 | async def read_users(commons: dict = Depends(common_parameters)):
18 | return {"message": "Hello Users!", "params": commons}
19 |
20 |
21 | client = TestClient(app)
22 |
23 |
24 | async def override_dependency(q: str = None):
25 | return {"q": q, "skip": 5, "limit": 10}
26 |
27 |
28 | app.dependency_overrides[common_parameters] = override_dependency
29 |
30 |
31 | def test_override_in_items():
32 | response = client.get("/items/")
33 | assert response.status_code == 200
34 | assert response.json() == {
35 | "message": "Hello Items!",
36 | "params": {"q": None, "skip": 5, "limit": 10},
37 | }
38 |
39 |
40 | def test_override_in_items_with_q():
41 | response = client.get("/items/?q=foo")
42 | assert response.status_code == 200
43 | assert response.json() == {
44 | "message": "Hello Items!",
45 | "params": {"q": "foo", "skip": 5, "limit": 10},
46 | }
47 |
48 |
49 | def test_override_in_items_with_params():
50 | response = client.get("/items/?q=foo&skip=100&limit=200")
51 | assert response.status_code == 200
52 | assert response.json() == {
53 | "message": "Hello Items!",
54 | "params": {"q": "foo", "skip": 5, "limit": 10},
55 | }
56 |
--------------------------------------------------------------------------------
/src/encoder/tutorial001.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from fastapi import FastAPI
4 | from fastapi.encoders import jsonable_encoder
5 | from pydantic import BaseModel
6 |
7 | fake_db = {}
8 |
9 |
10 | class Item(BaseModel):
11 | title: str
12 | timestamp: datetime
13 | description: str = None
14 |
15 |
16 | app = FastAPI()
17 |
18 |
19 | @app.put("/items/{id}")
20 | def update_item(id: str, item: Item):
21 | json_compatible_item_data = jsonable_encoder(item)
22 | fake_db[id] = json_compatible_item_data
23 |
--------------------------------------------------------------------------------
/src/events/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 | items = {}
6 |
7 |
8 | @app.on_event("startup")
9 | async def startup_event():
10 | items["foo"] = {"name": "Fighters"}
11 | items["bar"] = {"name": "Tenders"}
12 |
13 |
14 | @app.get("/items/{item_id}")
15 | async def read_items(item_id: str):
16 | return items[item_id]
17 |
--------------------------------------------------------------------------------
/src/events/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.on_event("shutdown")
7 | def shutdown_event():
8 | with open("log.txt", mode="a") as log:
9 | log.write("Application shutdown")
10 |
11 |
12 | @app.get("/items/")
13 | async def read_items():
14 | return [{"name": "Foo"}]
15 |
--------------------------------------------------------------------------------
/src/extending_openapi/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.openapi.utils import get_openapi
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/items/")
8 | async def read_items():
9 | return [{"name": "Foo"}]
10 |
11 |
12 | def custom_openapi():
13 | if app.openapi_schema:
14 | return app.openapi_schema
15 | openapi_schema = get_openapi(
16 | title="Custom title",
17 | version="2.5.0",
18 | description="This is a very custom OpenAPI schema",
19 | routes=app.routes,
20 | )
21 | openapi_schema["info"]["x-logo"] = {
22 | "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
23 | }
24 | app.openapi_schema = openapi_schema
25 | return app.openapi_schema
26 |
27 |
28 | app.openapi = custom_openapi
29 |
--------------------------------------------------------------------------------
/src/extending_openapi/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.openapi.docs import (
3 | get_redoc_html,
4 | get_swagger_ui_html,
5 | get_swagger_ui_oauth2_redirect_html,
6 | )
7 | from fastapi.staticfiles import StaticFiles
8 |
9 | app = FastAPI(docs_url=None, redoc_url=None)
10 |
11 | app.mount("/static", StaticFiles(directory="static"), name="static")
12 |
13 |
14 | @app.get("/docs", include_in_schema=False)
15 | async def custom_swagger_ui_html():
16 | return get_swagger_ui_html(
17 | openapi_url=app.openapi_url,
18 | title=app.title + " - Swagger UI",
19 | oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
20 | swagger_js_url="/static/swagger-ui-bundle.js",
21 | swagger_css_url="/static/swagger-ui.css",
22 | )
23 |
24 |
25 | @app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
26 | async def swagger_ui_redirect():
27 | return get_swagger_ui_oauth2_redirect_html()
28 |
29 |
30 | @app.get("/redoc", include_in_schema=False)
31 | async def redoc_html():
32 | return get_redoc_html(
33 | openapi_url=app.openapi_url,
34 | title=app.title + " - ReDoc",
35 | redoc_js_url="/static/redoc.standalone.js",
36 | )
37 |
38 |
39 | @app.get("/users/{username}")
40 | async def read_user(username: str):
41 | return {"message": f"Hello {username}"}
42 |
--------------------------------------------------------------------------------
/src/extra_data_types/tutorial001.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime, time, timedelta
2 | from uuid import UUID
3 |
4 | from fastapi import Body, FastAPI
5 |
6 | app = FastAPI()
7 |
8 |
9 | @app.put("/items/{item_id}")
10 | async def read_items(
11 | item_id: UUID,
12 | start_datetime: datetime = Body(None),
13 | end_datetime: datetime = Body(None),
14 | repeat_at: time = Body(None),
15 | process_after: timedelta = Body(None),
16 | ):
17 | start_process = start_datetime + process_after
18 | duration = end_datetime - start_process
19 | return {
20 | "item_id": item_id,
21 | "start_datetime": start_datetime,
22 | "end_datetime": end_datetime,
23 | "repeat_at": repeat_at,
24 | "process_after": process_after,
25 | "start_process": start_process,
26 | "duration": duration,
27 | }
28 |
--------------------------------------------------------------------------------
/src/extra_models/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel, EmailStr
3 |
4 | app = FastAPI()
5 |
6 |
7 | class UserIn(BaseModel):
8 | username: str
9 | password: str
10 | email: EmailStr
11 | full_name: str = None
12 |
13 |
14 | class UserOut(BaseModel):
15 | username: str
16 | email: EmailStr
17 | full_name: str = None
18 |
19 |
20 | class UserInDB(BaseModel):
21 | username: str
22 | hashed_password: str
23 | email: EmailStr
24 | full_name: str = None
25 |
26 |
27 | def fake_password_hasher(raw_password: str):
28 | return "supersecret" + raw_password
29 |
30 |
31 | def fake_save_user(user_in: UserIn):
32 | hashed_password = fake_password_hasher(user_in.password)
33 | user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
34 | print("User saved! ..not really")
35 | return user_in_db
36 |
37 |
38 | @app.post("/user/", response_model=UserOut)
39 | async def create_user(*, user_in: UserIn):
40 | user_saved = fake_save_user(user_in)
41 | return user_saved
42 |
--------------------------------------------------------------------------------
/src/extra_models/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel, EmailStr
3 |
4 | app = FastAPI()
5 |
6 |
7 | class UserBase(BaseModel):
8 | username: str
9 | email: EmailStr
10 | full_name: str = None
11 |
12 |
13 | class UserIn(UserBase):
14 | password: str
15 |
16 |
17 | class UserOut(UserBase):
18 | pass
19 |
20 |
21 | class UserInDB(UserBase):
22 | hashed_password: str
23 |
24 |
25 | def fake_password_hasher(raw_password: str):
26 | return "supersecret" + raw_password
27 |
28 |
29 | def fake_save_user(user_in: UserIn):
30 | hashed_password = fake_password_hasher(user_in.password)
31 | user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
32 | print("User saved! ..not really")
33 | return user_in_db
34 |
35 |
36 | @app.post("/user/", response_model=UserOut)
37 | async def create_user(*, user_in: UserIn):
38 | user_saved = fake_save_user(user_in)
39 | return user_saved
40 |
--------------------------------------------------------------------------------
/src/extra_models/tutorial003.py:
--------------------------------------------------------------------------------
1 | from typing import Union
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class BaseItem(BaseModel):
10 | description: str
11 | type: str
12 |
13 |
14 | class CarItem(BaseItem):
15 | type = "car"
16 |
17 |
18 | class PlaneItem(BaseItem):
19 | type = "plane"
20 | size: int
21 |
22 |
23 | items = {
24 | "item1": {"description": "All my friends drive a low rider", "type": "car"},
25 | "item2": {
26 | "description": "Music is my aeroplane, it's my aeroplane",
27 | "type": "plane",
28 | "size": 5,
29 | },
30 | }
31 |
32 |
33 | @app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
34 | async def read_item(item_id: str):
35 | return items[item_id]
36 |
--------------------------------------------------------------------------------
/src/extra_models/tutorial004.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str
12 |
13 |
14 | items = [
15 | {"name": "Foo", "description": "There comes my hero"},
16 | {"name": "Red", "description": "It's my aeroplane"},
17 | ]
18 |
19 |
20 | @app.get("/items/", response_model=List[Item])
21 | async def read_items():
22 | return items
23 |
--------------------------------------------------------------------------------
/src/extra_models/tutorial005.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 | from fastapi import FastAPI
4 |
5 | app = FastAPI()
6 |
7 |
8 | @app.get("/keyword-weights/", response_model=Dict[str, float])
9 | async def read_keyword_weights():
10 | return {"foo": 2.3, "bar": 3.4}
11 |
--------------------------------------------------------------------------------
/src/first_steps/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/")
7 | async def root():
8 | return {"message": "Hello World"}
9 |
--------------------------------------------------------------------------------
/src/first_steps/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | my_awesome_api = FastAPI()
4 |
5 |
6 | @my_awesome_api.get("/")
7 | async def root():
8 | return {"message": "Hello World"}
9 |
--------------------------------------------------------------------------------
/src/first_steps/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/")
7 | def root():
8 | return {"message": "Hello World"}
9 |
--------------------------------------------------------------------------------
/src/graphql/tutorial001.py:
--------------------------------------------------------------------------------
1 | import graphene
2 | from fastapi import FastAPI
3 | from starlette.graphql import GraphQLApp
4 |
5 |
6 | class Query(graphene.ObjectType):
7 | hello = graphene.String(name=graphene.String(default_value="stranger"))
8 |
9 | def resolve_hello(self, info, name):
10 | return "Hello " + name
11 |
12 |
13 | app = FastAPI()
14 | app.add_route("/", GraphQLApp(schema=graphene.Schema(query=Query)))
15 |
--------------------------------------------------------------------------------
/src/handling_errors/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, HTTPException
2 |
3 | app = FastAPI()
4 |
5 | items = {"foo": "The Foo Wrestlers"}
6 |
7 |
8 | @app.get("/items/{item_id}")
9 | async def read_item(item_id: str):
10 | if item_id not in items:
11 | raise HTTPException(status_code=404, detail="Item not found")
12 | return {"item": items[item_id]}
13 |
--------------------------------------------------------------------------------
/src/handling_errors/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, HTTPException
2 |
3 | app = FastAPI()
4 |
5 | items = {"foo": "The Foo Wrestlers"}
6 |
7 |
8 | @app.get("/items-header/{item_id}")
9 | async def read_item_header(item_id: str):
10 | if item_id not in items:
11 | raise HTTPException(
12 | status_code=404,
13 | detail="Item not found",
14 | headers={"X-Error": "There goes my error"},
15 | )
16 | return {"item": items[item_id]}
17 |
--------------------------------------------------------------------------------
/src/handling_errors/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Request
2 | from fastapi.responses import JSONResponse
3 |
4 |
5 | class UnicornException(Exception):
6 | def __init__(self, name: str):
7 | self.name = name
8 |
9 |
10 | app = FastAPI()
11 |
12 |
13 | @app.exception_handler(UnicornException)
14 | async def unicorn_exception_handler(request: Request, exc: UnicornException):
15 | return JSONResponse(
16 | status_code=418,
17 | content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
18 | )
19 |
20 |
21 | @app.get("/unicorns/{name}")
22 | async def read_unicorn(name: str):
23 | if name == "yolo":
24 | raise UnicornException(name=name)
25 | return {"unicorn_name": name}
26 |
--------------------------------------------------------------------------------
/src/handling_errors/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, HTTPException
2 | from fastapi.exceptions import RequestValidationError
3 | from fastapi.responses import PlainTextResponse
4 | from starlette.exceptions import HTTPException as StarletteHTTPException
5 |
6 | app = FastAPI()
7 |
8 |
9 | @app.exception_handler(StarletteHTTPException)
10 | async def http_exception_handler(request, exc):
11 | return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
12 |
13 |
14 | @app.exception_handler(RequestValidationError)
15 | async def validation_exception_handler(request, exc):
16 | return PlainTextResponse(str(exc), status_code=400)
17 |
18 |
19 | @app.get("/items/{item_id}")
20 | async def read_item(item_id: int):
21 | if item_id == 3:
22 | raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
23 | return {"item_id": item_id}
24 |
--------------------------------------------------------------------------------
/src/handling_errors/tutorial005.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Request, status
2 | from fastapi.encoders import jsonable_encoder
3 | from fastapi.exceptions import RequestValidationError
4 | from fastapi.responses import JSONResponse
5 | from pydantic import BaseModel
6 |
7 | app = FastAPI()
8 |
9 |
10 | @app.exception_handler(RequestValidationError)
11 | async def validation_exception_handler(request: Request, exc: RequestValidationError):
12 | return JSONResponse(
13 | status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
14 | content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}),
15 | )
16 |
17 |
18 | class Item(BaseModel):
19 | title: str
20 | size: int
21 |
22 |
23 | @app.post("/items/")
24 | async def create_item(item: Item):
25 | return item
26 |
--------------------------------------------------------------------------------
/src/handling_errors/tutorial006.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, HTTPException
2 | from fastapi.exception_handlers import (
3 | http_exception_handler,
4 | request_validation_exception_handler,
5 | )
6 | from fastapi.exceptions import RequestValidationError
7 | from starlette.exceptions import HTTPException as StarletteHTTPException
8 |
9 | app = FastAPI()
10 |
11 |
12 | @app.exception_handler(StarletteHTTPException)
13 | async def custom_http_exception_handler(request, exc):
14 | print(f"OMG! An HTTP error!: {exc}")
15 | return await http_exception_handler(request, exc)
16 |
17 |
18 | @app.exception_handler(RequestValidationError)
19 | async def validation_exception_handler(request, exc):
20 | print(f"OMG! The client sent invalid data!: {exc}")
21 | return await request_validation_exception_handler(request, exc)
22 |
23 |
24 | @app.get("/items/{item_id}")
25 | async def read_item(item_id: int):
26 | if item_id == 3:
27 | raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
28 | return {"item_id": item_id}
29 |
--------------------------------------------------------------------------------
/src/header_params/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Header
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(*, user_agent: str = Header(None)):
8 | return {"User-Agent": user_agent}
9 |
--------------------------------------------------------------------------------
/src/header_params/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Header
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(*, strange_header: str = Header(None, convert_underscores=False)):
8 | return {"strange_header": strange_header}
9 |
--------------------------------------------------------------------------------
/src/header_params/tutorial003.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI, Header
4 |
5 | app = FastAPI()
6 |
7 |
8 | @app.get("/items/")
9 | async def read_items(x_token: List[str] = Header(None)):
10 | return {"X-Token values": x_token}
11 |
--------------------------------------------------------------------------------
/src/middleware/tutorial001.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from fastapi import FastAPI, Request
4 |
5 | app = FastAPI()
6 |
7 |
8 | @app.middleware("http")
9 | async def add_process_time_header(request: Request, call_next):
10 | start_time = time.time()
11 | response = await call_next(request)
12 | process_time = time.time() - start_time
13 | response.headers["X-Process-Time"] = str(process_time)
14 | return response
15 |
--------------------------------------------------------------------------------
/src/nosql_databases/tutorial001.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | from couchbase import LOCKMODE_WAIT
7 | from couchbase.bucket import Bucket
8 | from couchbase.cluster import Cluster, PasswordAuthenticator
9 |
10 | USERPROFILE_DOC_TYPE = "userprofile"
11 |
12 |
13 | def get_bucket():
14 | cluster = Cluster(
15 | "couchbase://couchbasehost:8091?fetch_mutation_tokens=1&operation_timeout=30&n1ql_timeout=300"
16 | )
17 | authenticator = PasswordAuthenticator("username", "password")
18 | cluster.authenticate(authenticator)
19 | bucket: Bucket = cluster.open_bucket("bucket_name", lockmode=LOCKMODE_WAIT)
20 | bucket.timeout = 30
21 | bucket.n1ql_timeout = 300
22 | return bucket
23 |
24 |
25 | class User(BaseModel):
26 | username: str
27 | email: Optional[str] = None
28 | full_name: Optional[str] = None
29 | disabled: Optional[bool] = None
30 |
31 |
32 | class UserInDB(User):
33 | type: str = USERPROFILE_DOC_TYPE
34 | hashed_password: str
35 |
36 |
37 | def get_user(bucket: Bucket, username: str):
38 | doc_id = f"userprofile::{username}"
39 | result = bucket.get(doc_id, quiet=True)
40 | if not result.value:
41 | return None
42 | user = UserInDB(**result.value)
43 | return user
44 |
45 |
46 | # FastAPI specific code
47 | app = FastAPI()
48 |
49 |
50 | @app.get("/users/{username}", response_model=User)
51 | def read_user(username: str):
52 | bucket = get_bucket()
53 | user = get_user(bucket=bucket, username=username)
54 | return user
55 |
--------------------------------------------------------------------------------
/src/openapi_callbacks/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import APIRouter, FastAPI
2 | from fastapi.responses import JSONResponse
3 | from pydantic import BaseModel, HttpUrl
4 |
5 | app = FastAPI()
6 |
7 |
8 | class Invoice(BaseModel):
9 | id: str
10 | title: str = None
11 | customer: str
12 | total: float
13 |
14 |
15 | class InvoiceEvent(BaseModel):
16 | description: str
17 | paid: bool
18 |
19 |
20 | class InvoiceEventReceived(BaseModel):
21 | ok: bool
22 |
23 |
24 | invoices_callback_router = APIRouter(default_response_class=JSONResponse)
25 |
26 |
27 | @invoices_callback_router.post(
28 | "{$callback_url}/invoices/{$request.body.id}", response_model=InvoiceEventReceived,
29 | )
30 | def invoice_notification(body: InvoiceEvent):
31 | pass
32 |
33 |
34 | @app.post("/invoices/", callbacks=invoices_callback_router.routes)
35 | def create_invoice(invoice: Invoice, callback_url: HttpUrl = None):
36 | """
37 | Create an invoice.
38 |
39 | This will (let's imagine) let the API user (some external developer) create an
40 | invoice.
41 |
42 | And this path operation will:
43 |
44 | * Send the invoice to the client.
45 | * Collect the money from the client.
46 | * Send a notification back to the API user (the external developer), as a callback.
47 | * At this point is that the API will somehow send a POST request to the
48 | external API with the notification of the invoice event
49 | (e.g. "payment successful").
50 | """
51 | # Send the invoice, collect the money, send the notification (the callback)
52 | return {"msg": "Invoice received"}
53 |
--------------------------------------------------------------------------------
/src/path_operation_advanced_configuration/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/", operation_id="some_specific_id_you_define")
7 | async def read_items():
8 | return [{"item_id": "Foo"}]
9 |
--------------------------------------------------------------------------------
/src/path_operation_advanced_configuration/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.routing import APIRoute
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/items/")
8 | async def read_items():
9 | return [{"item_id": "Foo"}]
10 |
11 |
12 | def use_route_names_as_operation_ids(app: FastAPI) -> None:
13 | """
14 | Simplify operation IDs so that generated API clients have simpler function
15 | names.
16 |
17 | Should be called only after all routes have been added.
18 | """
19 | for route in app.routes:
20 | if isinstance(route, APIRoute):
21 | route.operation_id = route.name # in this case, 'read_items'
22 |
23 |
24 | use_route_names_as_operation_ids(app)
25 |
--------------------------------------------------------------------------------
/src/path_operation_advanced_configuration/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/", include_in_schema=False)
7 | async def read_items():
8 | return [{"item_id": "Foo"}]
9 |
--------------------------------------------------------------------------------
/src/path_operation_advanced_configuration/tutorial004.py:
--------------------------------------------------------------------------------
1 | from typing import Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = None
14 | tags: Set[str] = []
15 |
16 |
17 | @app.post("/items/", response_model=Item, summary="Create an item")
18 | async def create_item(*, item: Item):
19 | """
20 | Create an item with all the information:
21 |
22 | - **name**: each item must have a name
23 | - **description**: a long description
24 | - **price**: required
25 | - **tax**: if the item doesn't have tax, you can omit this
26 | - **tags**: a set of unique tag strings for this item
27 | \f
28 | :param item: User input.
29 | """
30 | return item
31 |
--------------------------------------------------------------------------------
/src/path_operation_configuration/tutorial001.py:
--------------------------------------------------------------------------------
1 | from typing import Set
2 |
3 | from fastapi import FastAPI, status
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = None
14 | tags: Set[str] = []
15 |
16 |
17 | @app.post("/items/", response_model=Item, status_code=status.HTTP_201_CREATED)
18 | async def create_item(*, item: Item):
19 | return item
20 |
--------------------------------------------------------------------------------
/src/path_operation_configuration/tutorial002.py:
--------------------------------------------------------------------------------
1 | from typing import Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = None
14 | tags: Set[str] = []
15 |
16 |
17 | @app.post("/items/", response_model=Item, tags=["items"])
18 | async def create_item(*, item: Item):
19 | return item
20 |
21 |
22 | @app.get("/items/", tags=["items"])
23 | async def read_items():
24 | return [{"name": "Foo", "price": 42}]
25 |
26 |
27 | @app.get("/users/", tags=["users"])
28 | async def read_users():
29 | return [{"username": "johndoe"}]
30 |
--------------------------------------------------------------------------------
/src/path_operation_configuration/tutorial003.py:
--------------------------------------------------------------------------------
1 | from typing import Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = None
14 | tags: Set[str] = []
15 |
16 |
17 | @app.post(
18 | "/items/",
19 | response_model=Item,
20 | summary="Create an item",
21 | description="Create an item with all the information, name, description, price, tax and a set of unique tags",
22 | )
23 | async def create_item(*, item: Item):
24 | return item
25 |
--------------------------------------------------------------------------------
/src/path_operation_configuration/tutorial004.py:
--------------------------------------------------------------------------------
1 | from typing import Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = None
14 | tags: Set[str] = []
15 |
16 |
17 | @app.post("/items/", response_model=Item, summary="Create an item")
18 | async def create_item(*, item: Item):
19 | """
20 | Create an item with all the information:
21 |
22 | - **name**: each item must have a name
23 | - **description**: a long description
24 | - **price**: required
25 | - **tax**: if the item doesn't have tax, you can omit this
26 | - **tags**: a set of unique tag strings for this item
27 | """
28 | return item
29 |
--------------------------------------------------------------------------------
/src/path_operation_configuration/tutorial005.py:
--------------------------------------------------------------------------------
1 | from typing import Set
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = None
14 | tags: Set[str] = []
15 |
16 |
17 | @app.post(
18 | "/items/",
19 | response_model=Item,
20 | summary="Create an item",
21 | response_description="The created item",
22 | )
23 | async def create_item(*, item: Item):
24 | """
25 | Create an item with all the information:
26 |
27 | - **name**: each item must have a name
28 | - **description**: a long description
29 | - **price**: required
30 | - **tax**: if the item doesn't have tax, you can omit this
31 | - **tags**: a set of unique tag strings for this item
32 | """
33 | return item
34 |
--------------------------------------------------------------------------------
/src/path_operation_configuration/tutorial006.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/", tags=["items"])
7 | async def read_items():
8 | return [{"name": "Foo", "price": 42}]
9 |
10 |
11 | @app.get("/users/", tags=["users"])
12 | async def read_users():
13 | return [{"username": "johndoe"}]
14 |
15 |
16 | @app.get("/elements/", tags=["items"], deprecated=True)
17 | async def read_elements():
18 | return [{"item_id": "Foo"}]
19 |
--------------------------------------------------------------------------------
/src/path_params/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_item(item_id):
8 | return {"item_id": item_id}
9 |
--------------------------------------------------------------------------------
/src/path_params/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_item(item_id: int):
8 | return {"item_id": item_id}
9 |
--------------------------------------------------------------------------------
/src/path_params/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/users/me")
7 | async def read_user_me():
8 | return {"user_id": "the current user"}
9 |
10 |
11 | @app.get("/users/{user_id}")
12 | async def read_user(user_id: str):
13 | return {"user_id": user_id}
14 |
--------------------------------------------------------------------------------
/src/path_params/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/files/{file_path:path}")
7 | async def read_user_me(file_path: str):
8 | return {"file_path": file_path}
9 |
--------------------------------------------------------------------------------
/src/path_params/tutorial005.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 | from fastapi import FastAPI
4 |
5 |
6 | class ModelName(str, Enum):
7 | alexnet = "alexnet"
8 | resnet = "resnet"
9 | lenet = "lenet"
10 |
11 |
12 | app = FastAPI()
13 |
14 |
15 | @app.get("/model/{model_name}")
16 | async def get_model(model_name: ModelName):
17 | if model_name == ModelName.alexnet:
18 | return {"model_name": model_name, "message": "Deep Learning FTW!"}
19 | if model_name.value == "lenet":
20 | return {"model_name": model_name, "message": "LeCNN all the images"}
21 | return {"model_name": model_name, "message": "Have some residuals"}
22 |
--------------------------------------------------------------------------------
/src/path_params_numeric_validations/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Path, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_items(
8 | item_id: int = Path(..., title="The ID of the item to get"),
9 | q: str = Query(None, alias="item-query"),
10 | ):
11 | results = {"item_id": item_id}
12 | if q:
13 | results.update({"q": q})
14 | return results
15 |
--------------------------------------------------------------------------------
/src/path_params_numeric_validations/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Path
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_items(
8 | q: str, item_id: int = Path(..., title="The ID of the item to get")
9 | ):
10 | results = {"item_id": item_id}
11 | if q:
12 | results.update({"q": q})
13 | return results
14 |
--------------------------------------------------------------------------------
/src/path_params_numeric_validations/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Path
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_items(
8 | *, item_id: int = Path(..., title="The ID of the item to get"), q: str
9 | ):
10 | results = {"item_id": item_id}
11 | if q:
12 | results.update({"q": q})
13 | return results
14 |
--------------------------------------------------------------------------------
/src/path_params_numeric_validations/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Path
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_items(
8 | *, item_id: int = Path(..., title="The ID of the item to get", ge=1), q: str
9 | ):
10 | results = {"item_id": item_id}
11 | if q:
12 | results.update({"q": q})
13 | return results
14 |
--------------------------------------------------------------------------------
/src/path_params_numeric_validations/tutorial005.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Path
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_items(
8 | *,
9 | item_id: int = Path(..., title="The ID of the item to get", gt=0, le=1000),
10 | q: str,
11 | ):
12 | results = {"item_id": item_id}
13 | if q:
14 | results.update({"q": q})
15 | return results
16 |
--------------------------------------------------------------------------------
/src/path_params_numeric_validations/tutorial006.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Path, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_items(
8 | *,
9 | item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
10 | q: str,
11 | size: float = Query(..., gt=0, lt=10.5)
12 | ):
13 | results = {"item_id": item_id}
14 | if q:
15 | results.update({"q": q})
16 | return results
17 |
--------------------------------------------------------------------------------
/src/python_types/tutorial001.py:
--------------------------------------------------------------------------------
1 | def get_full_name(first_name, last_name):
2 | full_name = first_name.title() + " " + last_name.title()
3 | return full_name
4 |
5 |
6 | print(get_full_name("john", "doe"))
7 |
--------------------------------------------------------------------------------
/src/python_types/tutorial002.py:
--------------------------------------------------------------------------------
1 | def get_full_name(first_name: str, last_name: str):
2 | full_name = first_name.title() + " " + last_name.title()
3 | return full_name
4 |
5 |
6 | print(get_full_name("john", "doe"))
7 |
--------------------------------------------------------------------------------
/src/python_types/tutorial003.py:
--------------------------------------------------------------------------------
1 | def get_name_with_age(name: str, age: int):
2 | name_with_age = name + " is this old: " + age
3 | return name_with_age
4 |
--------------------------------------------------------------------------------
/src/python_types/tutorial004.py:
--------------------------------------------------------------------------------
1 | def get_name_with_age(name: str, age: int):
2 | name_with_age = name + " is this old: " + str(age)
3 | return name_with_age
4 |
--------------------------------------------------------------------------------
/src/python_types/tutorial005.py:
--------------------------------------------------------------------------------
1 | def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
2 | return item_a, item_b, item_c, item_d, item_d, item_e
3 |
--------------------------------------------------------------------------------
/src/python_types/tutorial006.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 |
4 | def process_items(items: List[str]):
5 | for item in items:
6 | print(item)
7 |
--------------------------------------------------------------------------------
/src/python_types/tutorial007.py:
--------------------------------------------------------------------------------
1 | from typing import Set, Tuple
2 |
3 |
4 | def process_items(items_t: Tuple[int], items_s: Set[bytes]):
5 | return items_t, items_s
6 |
--------------------------------------------------------------------------------
/src/python_types/tutorial008.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 |
4 | def process_items(prices: Dict[str, float]):
5 | for item_name, item_price in prices.items():
6 | print(item_name)
7 | print(item_price)
8 |
--------------------------------------------------------------------------------
/src/python_types/tutorial009.py:
--------------------------------------------------------------------------------
1 | class Person:
2 | def __init__(self, name: str):
3 | self.name = name
4 |
5 |
6 | def get_person_name(one_person: Person):
7 | return one_person.name
8 |
--------------------------------------------------------------------------------
/src/python_types/tutorial010.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | from typing import List
3 |
4 | from pydantic import BaseModel
5 |
6 |
7 | class User(BaseModel):
8 | id: int
9 | name = "John Doe"
10 | signup_ts: datetime = None
11 | friends: List[int] = []
12 |
13 |
14 | external_data = {
15 | "id": "123",
16 | "signup_ts": "2017-06-01 12:22",
17 | "friends": [1, "2", b"3"],
18 | }
19 | user = User(**external_data)
20 | print(user)
21 | # > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
22 | print(user.id)
23 | # > 123
24 |
--------------------------------------------------------------------------------
/src/query_params/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 | fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
6 |
7 |
8 | @app.get("/items/")
9 | async def read_item(skip: int = 0, limit: int = 10):
10 | return fake_items_db[skip : skip + limit]
11 |
--------------------------------------------------------------------------------
/src/query_params/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_item(item_id: str, q: str = None):
8 | if q:
9 | return {"item_id": item_id, "q": q}
10 | return {"item_id": item_id}
11 |
--------------------------------------------------------------------------------
/src/query_params/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_item(item_id: str, q: str = None, short: bool = False):
8 | item = {"item_id": item_id}
9 | if q:
10 | item.update({"q": q})
11 | if not short:
12 | item.update(
13 | {"description": "This is an amazing item that has a long description"}
14 | )
15 | return item
16 |
--------------------------------------------------------------------------------
/src/query_params/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/users/{user_id}/items/{item_id}")
7 | async def read_user_item(
8 | user_id: int, item_id: str, q: str = None, short: bool = False
9 | ):
10 | item = {"item_id": item_id, "owner_id": user_id}
11 | if q:
12 | item.update({"q": q})
13 | if not short:
14 | item.update(
15 | {"description": "This is an amazing item that has a long description"}
16 | )
17 | return item
18 |
--------------------------------------------------------------------------------
/src/query_params/tutorial005.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_user_item(item_id: str, needy: str):
8 | item = {"item_id": item_id, "needy": needy}
9 | return item
10 |
--------------------------------------------------------------------------------
/src/query_params/tutorial006.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | async def read_user_item(item_id: str, needy: str, skip: int = 0, limit: int = None):
8 | item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
9 | return item
10 |
--------------------------------------------------------------------------------
/src/query_params/tutorial007.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from fastapi import FastAPI
4 |
5 | app = FastAPI()
6 |
7 |
8 | @app.get("/items/{item_id}")
9 | async def read_user_item(item_id: str, limit: Optional[int] = None):
10 | item = {"item_id": item_id, "limit": limit}
11 | return item
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(q: str = None):
8 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
9 | if q:
10 | results.update({"q": q})
11 | return results
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(q: str = Query(None, max_length=50)):
8 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
9 | if q:
10 | results.update({"q": q})
11 | return results
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(q: str = Query(None, min_length=3, max_length=50)):
8 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
9 | if q:
10 | results.update({"q": q})
11 | return results
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial004.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(
8 | q: str = Query(None, min_length=3, max_length=50, regex="^fixedquery$")
9 | ):
10 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
11 | if q:
12 | results.update({"q": q})
13 | return results
14 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial005.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(q: str = Query("fixedquery", min_length=3)):
8 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
9 | if q:
10 | results.update({"q": q})
11 | return results
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial006.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(q: str = Query(..., min_length=3)):
8 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
9 | if q:
10 | results.update({"q": q})
11 | return results
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial007.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(q: str = Query(None, title="Query string", min_length=3)):
8 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
9 | if q:
10 | results.update({"q": q})
11 | return results
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial008.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(
8 | q: str = Query(
9 | None,
10 | title="Query string",
11 | description="Query string for the items to search in the database that have a good match",
12 | min_length=3,
13 | )
14 | ):
15 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
16 | if q:
17 | results.update({"q": q})
18 | return results
19 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial009.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(q: str = Query(None, alias="item-query")):
8 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
9 | if q:
10 | results.update({"q": q})
11 | return results
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial010.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(
8 | q: str = Query(
9 | None,
10 | alias="item-query",
11 | title="Query string",
12 | description="Query string for the items to search in the database that have a good match",
13 | min_length=3,
14 | max_length=50,
15 | regex="^fixedquery$",
16 | deprecated=True,
17 | )
18 | ):
19 | results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
20 | if q:
21 | results.update({"q": q})
22 | return results
23 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial011.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI, Query
4 |
5 | app = FastAPI()
6 |
7 |
8 | @app.get("/items/")
9 | async def read_items(q: List[str] = Query(None)):
10 | query_items = {"q": q}
11 | return query_items
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial012.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI, Query
4 |
5 | app = FastAPI()
6 |
7 |
8 | @app.get("/items/")
9 | async def read_items(q: List[str] = Query(["foo", "bar"])):
10 | query_items = {"q": q}
11 | return query_items
12 |
--------------------------------------------------------------------------------
/src/query_params_str_validations/tutorial013.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Query
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/")
7 | async def read_items(q: list = Query(None)):
8 | query_items = {"q": q}
9 | return query_items
10 |
--------------------------------------------------------------------------------
/src/request_files/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, File, UploadFile
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.post("/files/")
7 | async def create_file(file: bytes = File(...)):
8 | return {"file_size": len(file)}
9 |
10 |
11 | @app.post("/uploadfile/")
12 | async def create_upload_file(file: UploadFile = File(...)):
13 | return {"filename": file.filename}
14 |
--------------------------------------------------------------------------------
/src/request_files/tutorial002.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI, File, UploadFile
4 | from fastapi.responses import HTMLResponse
5 |
6 | app = FastAPI()
7 |
8 |
9 | @app.post("/files/")
10 | async def create_files(files: List[bytes] = File(...)):
11 | return {"file_sizes": [len(file) for file in files]}
12 |
13 |
14 | @app.post("/uploadfiles/")
15 | async def create_upload_files(files: List[UploadFile] = File(...)):
16 | return {"filenames": [file.filename for file in files]}
17 |
18 |
19 | @app.get("/")
20 | async def main():
21 | content = """
22 |
23 |
27 |
31 |
32 | """
33 | return HTMLResponse(content=content)
34 |
--------------------------------------------------------------------------------
/src/request_forms/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Form
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.post("/login/")
7 | async def login(*, username: str = Form(...), password: str = Form(...)):
8 | return {"username": username}
9 |
--------------------------------------------------------------------------------
/src/request_forms_and_files/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, File, Form, UploadFile
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.post("/files/")
7 | async def create_file(
8 | file: bytes = File(...), fileb: UploadFile = File(...), token: str = Form(...)
9 | ):
10 | return {
11 | "file_size": len(file),
12 | "token": token,
13 | "fileb_content_type": fileb.content_type,
14 | }
15 |
--------------------------------------------------------------------------------
/src/response_change_status_code/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Response, status
2 |
3 | app = FastAPI()
4 |
5 | tasks = {"foo": "Listen to the Bar Fighters"}
6 |
7 |
8 | @app.put("/get-or-create-task/{task_id}", status_code=200)
9 | def get_or_create_task(task_id: str, response: Response):
10 | if task_id not in tasks:
11 | tasks[task_id] = "This didn't exist before"
12 | response.status_code = status.HTTP_201_CREATED
13 | return tasks[task_id]
14 |
--------------------------------------------------------------------------------
/src/response_cookies/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import JSONResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.post("/cookie/")
8 | def create_cookie():
9 | content = {"message": "Come to the dark side, we have cookies"}
10 | response = JSONResponse(content=content)
11 | response.set_cookie(key="fakesession", value="fake-cookie-session-value")
12 | return response
13 |
--------------------------------------------------------------------------------
/src/response_cookies/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Response
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.post("/cookie-and-object/")
7 | def create_cookie(response: Response):
8 | response.set_cookie(key="fakesession", value="fake-cookie-session-value")
9 | return {"message": "Come to the dark side, we have cookies"}
10 |
--------------------------------------------------------------------------------
/src/response_directly/tutorial001.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from fastapi import FastAPI
4 | from fastapi.encoders import jsonable_encoder
5 | from fastapi.responses import JSONResponse
6 | from pydantic import BaseModel
7 |
8 |
9 | class Item(BaseModel):
10 | title: str
11 | timestamp: datetime
12 | description: str = None
13 |
14 |
15 | app = FastAPI()
16 |
17 |
18 | @app.put("/items/{id}")
19 | def update_item(id: str, item: Item):
20 | json_compatible_item_data = jsonable_encoder(item)
21 | return JSONResponse(content=json_compatible_item_data)
22 |
--------------------------------------------------------------------------------
/src/response_directly/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Response
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/legacy/")
7 | def get_legacy_data():
8 | data = """
9 |
10 |
11 | Apply shampoo here.
12 |
13 |
14 | You'll have to use soap here.
15 |
16 |
17 | """
18 | return Response(content=data, media_type="application/xml")
19 |
--------------------------------------------------------------------------------
/src/response_headers/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.responses import JSONResponse
3 |
4 | app = FastAPI()
5 |
6 |
7 | @app.get("/headers/")
8 | def get_headers():
9 | content = {"message": "Hello World"}
10 | headers = {"X-Cat-Dog": "alone in the world", "Content-Language": "en-US"}
11 | return JSONResponse(content=content, headers=headers)
12 |
--------------------------------------------------------------------------------
/src/response_headers/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Response
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/headers-and-object/")
7 | def get_headers(response: Response):
8 | response.headers["X-Cat-Dog"] = "alone in the world"
9 | return {"message": "Hello World"}
10 |
--------------------------------------------------------------------------------
/src/response_model/tutorial001.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = None
14 | tags: List[str] = []
15 |
16 |
17 | @app.post("/items/", response_model=Item)
18 | async def create_item(item: Item):
19 | return item
20 |
--------------------------------------------------------------------------------
/src/response_model/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel, EmailStr
3 |
4 | app = FastAPI()
5 |
6 |
7 | class UserIn(BaseModel):
8 | username: str
9 | password: str
10 | email: EmailStr
11 | full_name: str = None
12 |
13 |
14 | # Don't do this in production!
15 | @app.post("/user/", response_model=UserIn)
16 | async def create_user(*, user: UserIn):
17 | return user
18 |
--------------------------------------------------------------------------------
/src/response_model/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel, EmailStr
3 |
4 | app = FastAPI()
5 |
6 |
7 | class UserIn(BaseModel):
8 | username: str
9 | password: str
10 | email: EmailStr
11 | full_name: str = None
12 |
13 |
14 | class UserOut(BaseModel):
15 | username: str
16 | email: EmailStr
17 | full_name: str = None
18 |
19 |
20 | @app.post("/user/", response_model=UserOut)
21 | async def create_user(*, user: UserIn):
22 | return user
23 |
--------------------------------------------------------------------------------
/src/response_model/tutorial004.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import FastAPI
4 | from pydantic import BaseModel
5 |
6 | app = FastAPI()
7 |
8 |
9 | class Item(BaseModel):
10 | name: str
11 | description: str = None
12 | price: float
13 | tax: float = 10.5
14 | tags: List[str] = []
15 |
16 |
17 | items = {
18 | "foo": {"name": "Foo", "price": 50.2},
19 | "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
20 | "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
21 | }
22 |
23 |
24 | @app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
25 | async def read_item(item_id: str):
26 | return items[item_id]
27 |
--------------------------------------------------------------------------------
/src/response_model/tutorial005.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = None
10 | price: float
11 | tax: float = 10.5
12 |
13 |
14 | items = {
15 | "foo": {"name": "Foo", "price": 50.2},
16 | "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
17 | "baz": {
18 | "name": "Baz",
19 | "description": "There goes my baz",
20 | "price": 50.2,
21 | "tax": 10.5,
22 | },
23 | }
24 |
25 |
26 | @app.get(
27 | "/items/{item_id}/name",
28 | response_model=Item,
29 | response_model_include={"name", "description"},
30 | )
31 | async def read_item_name(item_id: str):
32 | return items[item_id]
33 |
34 |
35 | @app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
36 | async def read_item_public_data(item_id: str):
37 | return items[item_id]
38 |
--------------------------------------------------------------------------------
/src/response_model/tutorial006.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from pydantic import BaseModel
3 |
4 | app = FastAPI()
5 |
6 |
7 | class Item(BaseModel):
8 | name: str
9 | description: str = None
10 | price: float
11 | tax: float = 10.5
12 |
13 |
14 | items = {
15 | "foo": {"name": "Foo", "price": 50.2},
16 | "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
17 | "baz": {
18 | "name": "Baz",
19 | "description": "There goes my baz",
20 | "price": 50.2,
21 | "tax": 10.5,
22 | },
23 | }
24 |
25 |
26 | @app.get(
27 | "/items/{item_id}/name",
28 | response_model=Item,
29 | response_model_include=["name", "description"],
30 | )
31 | async def read_item_name(item_id: str):
32 | return items[item_id]
33 |
34 |
35 | @app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
36 | async def read_item_public_data(item_id: str):
37 | return items[item_id]
38 |
--------------------------------------------------------------------------------
/src/response_status_code/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.post("/items/", status_code=201)
7 | async def create_item(name: str):
8 | return {"name": name}
9 |
--------------------------------------------------------------------------------
/src/response_status_code/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, status
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.post("/items/", status_code=status.HTTP_201_CREATED)
7 | async def create_item(name: str):
8 | return {"name": name}
9 |
--------------------------------------------------------------------------------
/src/security/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI
2 | from fastapi.security import OAuth2PasswordBearer
3 |
4 | app = FastAPI()
5 |
6 | oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
7 |
8 |
9 | @app.get("/items/")
10 | async def read_items(token: str = Depends(oauth2_scheme)):
11 | return {"token": token}
12 |
--------------------------------------------------------------------------------
/src/security/tutorial002.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from fastapi import Depends, FastAPI
4 | from fastapi.security import OAuth2PasswordBearer
5 | from pydantic import BaseModel
6 |
7 | app = FastAPI()
8 |
9 | oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
10 |
11 |
12 | class User(BaseModel):
13 | username: str
14 | email: Optional[str] = None
15 | full_name: Optional[str] = None
16 | disabled: Optional[bool] = None
17 |
18 |
19 | def fake_decode_token(token):
20 | return User(
21 | username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
22 | )
23 |
24 |
25 | async def get_current_user(token: str = Depends(oauth2_scheme)):
26 | user = fake_decode_token(token)
27 | return user
28 |
29 |
30 | @app.get("/users/me")
31 | async def read_users_me(current_user: User = Depends(get_current_user)):
32 | return current_user
33 |
--------------------------------------------------------------------------------
/src/security/tutorial003.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI, HTTPException, status
2 | from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
3 | from pydantic import BaseModel
4 |
5 | fake_users_db = {
6 | "johndoe": {
7 | "username": "johndoe",
8 | "full_name": "John Doe",
9 | "email": "johndoe@example.com",
10 | "hashed_password": "fakehashedsecret",
11 | "disabled": False,
12 | },
13 | "alice": {
14 | "username": "alice",
15 | "full_name": "Alice Wonderson",
16 | "email": "alice@example.com",
17 | "hashed_password": "fakehashedsecret2",
18 | "disabled": True,
19 | },
20 | }
21 |
22 | app = FastAPI()
23 |
24 |
25 | def fake_hash_password(password: str):
26 | return "fakehashed" + password
27 |
28 |
29 | oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
30 |
31 |
32 | class User(BaseModel):
33 | username: str
34 | email: str = None
35 | full_name: str = None
36 | disabled: bool = None
37 |
38 |
39 | class UserInDB(User):
40 | hashed_password: str
41 |
42 |
43 | def get_user(db, username: str):
44 | if username in db:
45 | user_dict = db[username]
46 | return UserInDB(**user_dict)
47 |
48 |
49 | def fake_decode_token(token):
50 | # This doesn't provide any security at all
51 | # Check the next version
52 | user = get_user(fake_users_db, token)
53 | return user
54 |
55 |
56 | async def get_current_user(token: str = Depends(oauth2_scheme)):
57 | user = fake_decode_token(token)
58 | if not user:
59 | raise HTTPException(
60 | status_code=status.HTTP_401_UNAUTHORIZED,
61 | detail="Invalid authentication credentials",
62 | headers={"WWW-Authenticate": "Bearer"},
63 | )
64 | return user
65 |
66 |
67 | async def get_current_active_user(current_user: User = Depends(get_current_user)):
68 | if current_user.disabled:
69 | raise HTTPException(status_code=400, detail="Inactive user")
70 | return current_user
71 |
72 |
73 | @app.post("/token")
74 | async def login(form_data: OAuth2PasswordRequestForm = Depends()):
75 | user_dict = fake_users_db.get(form_data.username)
76 | if not user_dict:
77 | raise HTTPException(status_code=400, detail="Incorrect username or password")
78 | user = UserInDB(**user_dict)
79 | hashed_password = fake_hash_password(form_data.password)
80 | if not hashed_password == user.hashed_password:
81 | raise HTTPException(status_code=400, detail="Incorrect username or password")
82 |
83 | return {"access_token": user.username, "token_type": "bearer"}
84 |
85 |
86 | @app.get("/users/me")
87 | async def read_users_me(current_user: User = Depends(get_current_active_user)):
88 | return current_user
89 |
--------------------------------------------------------------------------------
/src/security/tutorial006.py:
--------------------------------------------------------------------------------
1 | from fastapi import Depends, FastAPI
2 | from fastapi.security import HTTPBasic, HTTPBasicCredentials
3 |
4 | app = FastAPI()
5 |
6 | security = HTTPBasic()
7 |
8 |
9 | @app.get("/users/me")
10 | def read_current_user(credentials: HTTPBasicCredentials = Depends(security)):
11 | return {"username": credentials.username, "password": credentials.password}
12 |
--------------------------------------------------------------------------------
/src/security/tutorial007.py:
--------------------------------------------------------------------------------
1 | import secrets
2 |
3 | from fastapi import Depends, FastAPI, HTTPException, status
4 | from fastapi.security import HTTPBasic, HTTPBasicCredentials
5 |
6 | app = FastAPI()
7 |
8 | security = HTTPBasic()
9 |
10 |
11 | def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
12 | correct_username = secrets.compare_digest(credentials.username, "stanleyjobson")
13 | correct_password = secrets.compare_digest(credentials.password, "swordfish")
14 | if not (correct_username and correct_password):
15 | raise HTTPException(
16 | status_code=status.HTTP_401_UNAUTHORIZED,
17 | detail="Incorrect email or password",
18 | headers={"WWW-Authenticate": "Basic"},
19 | )
20 | return credentials.username
21 |
22 |
23 | @app.get("/users/me")
24 | def read_current_user(username: str = Depends(get_current_username)):
25 | return {"username": username}
26 |
--------------------------------------------------------------------------------
/src/sql_databases/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/src/sql_databases/__init__.py
--------------------------------------------------------------------------------
/src/sql_databases/sql_app/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/src/sql_databases/sql_app/__init__.py
--------------------------------------------------------------------------------
/src/sql_databases/sql_app/alt_main.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import Depends, FastAPI, HTTPException, Request, Response
4 | from sqlalchemy.orm import Session
5 |
6 | from . import crud, models, schemas
7 | from .database import SessionLocal, engine
8 |
9 | models.Base.metadata.create_all(bind=engine)
10 |
11 | app = FastAPI()
12 |
13 |
14 | @app.middleware("http")
15 | async def db_session_middleware(request: Request, call_next):
16 | response = Response("Internal server error", status_code=500)
17 | try:
18 | request.state.db = SessionLocal()
19 | response = await call_next(request)
20 | finally:
21 | request.state.db.close()
22 | return response
23 |
24 |
25 | # Dependency
26 | def get_db(request: Request):
27 | return request.state.db
28 |
29 |
30 | @app.post("/users/", response_model=schemas.User)
31 | def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
32 | db_user = crud.get_user_by_email(db, email=user.email)
33 | if db_user:
34 | raise HTTPException(status_code=400, detail="Email already registered")
35 | return crud.create_user(db=db, user=user)
36 |
37 |
38 | @app.get("/users/", response_model=List[schemas.User])
39 | def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
40 | users = crud.get_users(db, skip=skip, limit=limit)
41 | return users
42 |
43 |
44 | @app.get("/users/{user_id}", response_model=schemas.User)
45 | def read_user(user_id: int, db: Session = Depends(get_db)):
46 | db_user = crud.get_user(db, user_id=user_id)
47 | if db_user is None:
48 | raise HTTPException(status_code=404, detail="User not found")
49 | return db_user
50 |
51 |
52 | @app.post("/users/{user_id}/items/", response_model=schemas.Item)
53 | def create_item_for_user(
54 | user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)
55 | ):
56 | return crud.create_user_item(db=db, item=item, user_id=user_id)
57 |
58 |
59 | @app.get("/items/", response_model=List[schemas.Item])
60 | def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
61 | items = crud.get_items(db, skip=skip, limit=limit)
62 | return items
63 |
--------------------------------------------------------------------------------
/src/sql_databases/sql_app/crud.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy.orm import Session
2 |
3 | from . import models, schemas
4 |
5 |
6 | def get_user(db: Session, user_id: int):
7 | return db.query(models.User).filter(models.User.id == user_id).first()
8 |
9 |
10 | def get_user_by_email(db: Session, email: str):
11 | return db.query(models.User).filter(models.User.email == email).first()
12 |
13 |
14 | def get_users(db: Session, skip: int = 0, limit: int = 100):
15 | return db.query(models.User).offset(skip).limit(limit).all()
16 |
17 |
18 | def create_user(db: Session, user: schemas.UserCreate):
19 | fake_hashed_password = user.password + "notreallyhashed"
20 | db_user = models.User(email=user.email, hashed_password=fake_hashed_password)
21 | db.add(db_user)
22 | db.commit()
23 | db.refresh(db_user)
24 | return db_user
25 |
26 |
27 | def get_items(db: Session, skip: int = 0, limit: int = 100):
28 | return db.query(models.Item).offset(skip).limit(limit).all()
29 |
30 |
31 | def create_user_item(db: Session, item: schemas.ItemCreate, user_id: int):
32 | db_item = models.Item(**item.dict(), owner_id=user_id)
33 | db.add(db_item)
34 | db.commit()
35 | db.refresh(db_item)
36 | return db_item
37 |
--------------------------------------------------------------------------------
/src/sql_databases/sql_app/database.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import create_engine
2 | from sqlalchemy.ext.declarative import declarative_base
3 | from sqlalchemy.orm import sessionmaker
4 |
5 | SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
6 | # SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"
7 |
8 | engine = create_engine(
9 | SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
10 | )
11 | SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
12 |
13 | Base = declarative_base()
14 |
--------------------------------------------------------------------------------
/src/sql_databases/sql_app/main.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import Depends, FastAPI, HTTPException
4 | from sqlalchemy.orm import Session
5 |
6 | from . import crud, models, schemas
7 | from .database import SessionLocal, engine
8 |
9 | models.Base.metadata.create_all(bind=engine)
10 |
11 | app = FastAPI()
12 |
13 |
14 | # Dependency
15 | def get_db():
16 | try:
17 | db = SessionLocal()
18 | yield db
19 | finally:
20 | db.close()
21 |
22 |
23 | @app.post("/users/", response_model=schemas.User)
24 | def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
25 | db_user = crud.get_user_by_email(db, email=user.email)
26 | if db_user:
27 | raise HTTPException(status_code=400, detail="Email already registered")
28 | return crud.create_user(db=db, user=user)
29 |
30 |
31 | @app.get("/users/", response_model=List[schemas.User])
32 | def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
33 | users = crud.get_users(db, skip=skip, limit=limit)
34 | return users
35 |
36 |
37 | @app.get("/users/{user_id}", response_model=schemas.User)
38 | def read_user(user_id: int, db: Session = Depends(get_db)):
39 | db_user = crud.get_user(db, user_id=user_id)
40 | if db_user is None:
41 | raise HTTPException(status_code=404, detail="User not found")
42 | return db_user
43 |
44 |
45 | @app.post("/users/{user_id}/items/", response_model=schemas.Item)
46 | def create_item_for_user(
47 | user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)
48 | ):
49 | return crud.create_user_item(db=db, item=item, user_id=user_id)
50 |
51 |
52 | @app.get("/items/", response_model=List[schemas.Item])
53 | def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
54 | items = crud.get_items(db, skip=skip, limit=limit)
55 | return items
56 |
--------------------------------------------------------------------------------
/src/sql_databases/sql_app/models.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
2 | from sqlalchemy.orm import relationship
3 |
4 | from .database import Base
5 |
6 |
7 | class User(Base):
8 | __tablename__ = "users"
9 |
10 | id = Column(Integer, primary_key=True, index=True)
11 | email = Column(String, unique=True, index=True)
12 | hashed_password = Column(String)
13 | is_active = Column(Boolean, default=True)
14 |
15 | items = relationship("Item", back_populates="owner")
16 |
17 |
18 | class Item(Base):
19 | __tablename__ = "items"
20 |
21 | id = Column(Integer, primary_key=True, index=True)
22 | title = Column(String, index=True)
23 | description = Column(String, index=True)
24 | owner_id = Column(Integer, ForeignKey("users.id"))
25 |
26 | owner = relationship("User", back_populates="items")
27 |
--------------------------------------------------------------------------------
/src/sql_databases/sql_app/schemas.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from pydantic import BaseModel
4 |
5 |
6 | class ItemBase(BaseModel):
7 | title: str
8 | description: str = None
9 |
10 |
11 | class ItemCreate(ItemBase):
12 | pass
13 |
14 |
15 | class Item(ItemBase):
16 | id: int
17 | owner_id: int
18 |
19 | class Config:
20 | orm_mode = True
21 |
22 |
23 | class UserBase(BaseModel):
24 | email: str
25 |
26 |
27 | class UserCreate(UserBase):
28 | password: str
29 |
30 |
31 | class User(UserBase):
32 | id: int
33 | is_active: bool
34 | items: List[Item] = []
35 |
36 | class Config:
37 | orm_mode = True
38 |
--------------------------------------------------------------------------------
/src/sql_databases_peewee/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/src/sql_databases_peewee/__init__.py
--------------------------------------------------------------------------------
/src/sql_databases_peewee/sql_app/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/src/sql_databases_peewee/sql_app/__init__.py
--------------------------------------------------------------------------------
/src/sql_databases_peewee/sql_app/crud.py:
--------------------------------------------------------------------------------
1 | from . import models, schemas
2 |
3 |
4 | def get_user(user_id: int):
5 | return models.User.filter(models.User.id == user_id).first()
6 |
7 |
8 | def get_user_by_email(email: str):
9 | return models.User.filter(models.User.email == email).first()
10 |
11 |
12 | def get_users(skip: int = 0, limit: int = 100):
13 | return list(models.User.select().offset(skip).limit(limit))
14 |
15 |
16 | def create_user(user: schemas.UserCreate):
17 | fake_hashed_password = user.password + "notreallyhashed"
18 | db_user = models.User(email=user.email, hashed_password=fake_hashed_password)
19 | db_user.save()
20 | return db_user
21 |
22 |
23 | def get_items(skip: int = 0, limit: int = 100):
24 | return list(models.Item.select().offset(skip).limit(limit))
25 |
26 |
27 | def create_user_item(item: schemas.ItemCreate, user_id: int):
28 | db_item = models.Item(**item.dict(), owner_id=user_id)
29 | db_item.save()
30 | return db_item
31 |
--------------------------------------------------------------------------------
/src/sql_databases_peewee/sql_app/database.py:
--------------------------------------------------------------------------------
1 | from contextvars import ContextVar
2 |
3 | import peewee
4 |
5 | DATABASE_NAME = "test.db"
6 | db_state_default = {"closed": None, "conn": None, "ctx": None, "transactions": None}
7 | db_state = ContextVar("db_state", default=db_state_default.copy())
8 |
9 |
10 | class PeeweeConnectionState(peewee._ConnectionState):
11 | def __init__(self, **kwargs):
12 | super().__setattr__("_state", db_state)
13 | super().__init__(**kwargs)
14 |
15 | def __setattr__(self, name, value):
16 | self._state.get()[name] = value
17 |
18 | def __getattr__(self, name):
19 | return self._state.get()[name]
20 |
21 |
22 | db = peewee.SqliteDatabase(DATABASE_NAME, check_same_thread=False)
23 |
24 | db._state = PeeweeConnectionState()
25 |
--------------------------------------------------------------------------------
/src/sql_databases_peewee/sql_app/main.py:
--------------------------------------------------------------------------------
1 | import time
2 | from typing import List
3 |
4 | from fastapi import Depends, FastAPI, HTTPException
5 |
6 | from . import crud, database, models, schemas
7 | from .database import db_state_default
8 |
9 | database.db.connect()
10 | database.db.create_tables([models.User, models.Item])
11 | database.db.close()
12 |
13 | app = FastAPI()
14 |
15 | sleep_time = 10
16 |
17 |
18 | async def reset_db_state():
19 | database.db._state._state.set(db_state_default.copy())
20 | database.db._state.reset()
21 |
22 |
23 | def get_db(db_state=Depends(reset_db_state)):
24 | try:
25 | database.db.connect()
26 | yield
27 | finally:
28 | if not database.db.is_closed():
29 | database.db.close()
30 |
31 |
32 | @app.post("/users/", response_model=schemas.User, dependencies=[Depends(get_db)])
33 | def create_user(user: schemas.UserCreate):
34 | db_user = crud.get_user_by_email(email=user.email)
35 | if db_user:
36 | raise HTTPException(status_code=400, detail="Email already registered")
37 | return crud.create_user(user=user)
38 |
39 |
40 | @app.get("/users/", response_model=List[schemas.User], dependencies=[Depends(get_db)])
41 | def read_users(skip: int = 0, limit: int = 100):
42 | users = crud.get_users(skip=skip, limit=limit)
43 | return users
44 |
45 |
46 | @app.get(
47 | "/users/{user_id}", response_model=schemas.User, dependencies=[Depends(get_db)]
48 | )
49 | def read_user(user_id: int):
50 | db_user = crud.get_user(user_id=user_id)
51 | if db_user is None:
52 | raise HTTPException(status_code=404, detail="User not found")
53 | return db_user
54 |
55 |
56 | @app.post(
57 | "/users/{user_id}/items/",
58 | response_model=schemas.Item,
59 | dependencies=[Depends(get_db)],
60 | )
61 | def create_item_for_user(user_id: int, item: schemas.ItemCreate):
62 | return crud.create_user_item(item=item, user_id=user_id)
63 |
64 |
65 | @app.get("/items/", response_model=List[schemas.Item], dependencies=[Depends(get_db)])
66 | def read_items(skip: int = 0, limit: int = 100):
67 | items = crud.get_items(skip=skip, limit=limit)
68 | return items
69 |
70 |
71 | @app.get(
72 | "/slowusers/", response_model=List[schemas.User], dependencies=[Depends(get_db)]
73 | )
74 | def read_slow_users(skip: int = 0, limit: int = 100):
75 | global sleep_time
76 | sleep_time = max(0, sleep_time - 1)
77 | time.sleep(sleep_time) # Fake long processing request
78 | users = crud.get_users(skip=skip, limit=limit)
79 | return users
80 |
--------------------------------------------------------------------------------
/src/sql_databases_peewee/sql_app/models.py:
--------------------------------------------------------------------------------
1 | import peewee
2 |
3 | from .database import db
4 |
5 |
6 | class User(peewee.Model):
7 | email = peewee.CharField(unique=True, index=True)
8 | hashed_password = peewee.CharField()
9 | is_active = peewee.BooleanField(default=True)
10 |
11 | class Meta:
12 | database = db
13 |
14 |
15 | class Item(peewee.Model):
16 | title = peewee.CharField(index=True)
17 | description = peewee.CharField(index=True)
18 | owner = peewee.ForeignKeyField(User, backref="items")
19 |
20 | class Meta:
21 | database = db
22 |
--------------------------------------------------------------------------------
/src/sql_databases_peewee/sql_app/schemas.py:
--------------------------------------------------------------------------------
1 | from typing import Any, List
2 |
3 | import peewee
4 | from pydantic import BaseModel
5 | from pydantic.utils import GetterDict
6 |
7 |
8 | class PeeweeGetterDict(GetterDict):
9 | def get(self, key: Any, default: Any = None):
10 | res = getattr(self._obj, key, default)
11 | if isinstance(res, peewee.ModelSelect):
12 | return list(res)
13 | return res
14 |
15 |
16 | class ItemBase(BaseModel):
17 | title: str
18 | description: str = None
19 |
20 |
21 | class ItemCreate(ItemBase):
22 | pass
23 |
24 |
25 | class Item(ItemBase):
26 | id: int
27 | owner_id: int
28 |
29 | class Config:
30 | orm_mode = True
31 | getter_dict = PeeweeGetterDict
32 |
33 |
34 | class UserBase(BaseModel):
35 | email: str
36 |
37 |
38 | class UserCreate(UserBase):
39 | password: str
40 |
41 |
42 | class User(UserBase):
43 | id: int
44 | is_active: bool
45 | items: List[Item] = []
46 |
47 | class Config:
48 | orm_mode = True
49 | getter_dict = PeeweeGetterDict
50 |
--------------------------------------------------------------------------------
/src/static_files/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.staticfiles import StaticFiles
3 |
4 | app = FastAPI()
5 |
6 | app.mount("/static", StaticFiles(directory="static"), name="static")
7 |
--------------------------------------------------------------------------------
/src/sub_applications/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/app")
7 | def read_main():
8 | return {"message": "Hello World from main app"}
9 |
10 |
11 | subapi = FastAPI(openapi_prefix="/subapi")
12 |
13 |
14 | @subapi.get("/sub")
15 | def read_sub():
16 | return {"message": "Hello World from sub API"}
17 |
18 |
19 | app.mount("/subapi", subapi)
20 |
--------------------------------------------------------------------------------
/src/templates/static/styles.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | color: green;
3 | }
4 |
--------------------------------------------------------------------------------
/src/templates/templates/item.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Item Details
4 |
5 |
6 |
7 | Item ID: {{ id }}
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/templates/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Request
2 | from fastapi.staticfiles import StaticFiles
3 | from fastapi.templating import Jinja2Templates
4 |
5 | app = FastAPI()
6 |
7 | app.mount("/static", StaticFiles(directory="static"), name="static")
8 |
9 |
10 | templates = Jinja2Templates(directory="templates")
11 |
12 |
13 | @app.get("/items/{id}")
14 | async def read_item(request: Request, id: str):
15 | return templates.TemplateResponse("item.html", {"request": request, "id": id})
16 |
--------------------------------------------------------------------------------
/src/using_request_directly/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, Request
2 |
3 | app = FastAPI()
4 |
5 |
6 | @app.get("/items/{item_id}")
7 | def read_root(item_id: str, request: Request):
8 | client_host = request.client.host
9 | return {"client_host": client_host, "item_id": item_id}
10 |
--------------------------------------------------------------------------------
/src/websockets/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/fastapi-docs-cn/68f1b5d3fb8186c095027950a2d39116a514a623/src/websockets/__init__.py
--------------------------------------------------------------------------------
/src/websockets/tutorial001.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI, WebSocket
2 | from fastapi.responses import HTMLResponse
3 |
4 | app = FastAPI()
5 |
6 | html = """
7 |
8 |
9 |
10 | Chat
11 |
12 |
13 | WebSocket Chat
14 |
18 |
20 |
36 |
37 |
38 | """
39 |
40 |
41 | @app.get("/")
42 | async def get():
43 | return HTMLResponse(html)
44 |
45 |
46 | @app.websocket("/ws")
47 | async def websocket_endpoint(websocket: WebSocket):
48 | await websocket.accept()
49 | while True:
50 | data = await websocket.receive_text()
51 | await websocket.send_text(f"Message text was: {data}")
52 |
--------------------------------------------------------------------------------
/src/websockets/tutorial002.py:
--------------------------------------------------------------------------------
1 | from fastapi import Cookie, Depends, FastAPI, Header, WebSocket, status
2 | from fastapi.responses import HTMLResponse
3 |
4 | app = FastAPI()
5 |
6 | html = """
7 |
8 |
9 |
10 | Chat
11 |
12 |
13 | WebSocket Chat
14 |
21 |
23 |
43 |
44 |
45 | """
46 |
47 |
48 | @app.get("/")
49 | async def get():
50 | return HTMLResponse(html)
51 |
52 |
53 | async def get_cookie_or_client(
54 | websocket: WebSocket, session: str = Cookie(None), x_client: str = Header(None)
55 | ):
56 | if session is None and x_client is None:
57 | await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
58 | return session or x_client
59 |
60 |
61 | @app.websocket("/items/{item_id}/ws")
62 | async def websocket_endpoint(
63 | websocket: WebSocket,
64 | item_id: int,
65 | q: str = None,
66 | cookie_or_client: str = Depends(get_cookie_or_client),
67 | ):
68 | await websocket.accept()
69 | while True:
70 | data = await websocket.receive_text()
71 | await websocket.send_text(
72 | f"Session Cookie or X-Client Header value is: {cookie_or_client}"
73 | )
74 | if q is not None:
75 | await websocket.send_text(f"Query parameter q is: {q}")
76 | await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
77 |
--------------------------------------------------------------------------------
/src/wsgi/tutorial001.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, escape, request
2 | from fastapi import FastAPI
3 | from fastapi.middleware.wsgi import WSGIMiddleware
4 |
5 | flask_app = Flask(__name__)
6 |
7 |
8 | @flask_app.route("/")
9 | def flask_main():
10 | name = request.args.get("name", "World")
11 | return f"Hello, {escape(name)} from Flask!"
12 |
13 |
14 | app = FastAPI()
15 |
16 |
17 | @app.get("/v2")
18 | def read_main():
19 | return {"message": "Hello World"}
20 |
21 |
22 | app.mount("/v1", WSGIMiddleware(flask_app))
23 |
--------------------------------------------------------------------------------
/tutorial/README.md:
--------------------------------------------------------------------------------
1 | This tutorial shows you how to use **FastAPI** with most of its features, step by step.
2 |
3 | Each section gradually builds on the previous ones, but it's structured to separate topics, so that you can go directly to any specific one to solve your specific API needs.
4 |
5 | It is also built to work as a future reference.
6 |
7 | So you can come back and see exactly what you need.
8 |
9 | ## Run the code
10 |
11 | All the code blocks can be copied and used directly (they are actually tested Python files).
12 |
13 | To run any of the examples, copy the code to a file `main.py`, and start `uvicorn` with:
14 |
15 |
16 |
17 | ```console
18 | $ uvicorn main:app --reload
19 |
20 | INFO : Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
21 | INFO : Started reloader process [28720]
22 | INFO : Started server process [28722]
23 | INFO : Waiting for application startup.
24 | INFO : Application startup complete.
25 | ```
26 |
27 |
28 |
29 | It is **HIGHLY encouraged** that you write or copy the code, edit it and run it locally.
30 |
31 | Using it in your editor is what really shows you the benefits of FastAPI, seeing how little code you have to write, all the type checks, autocompletion, etc.
32 |
33 | ---
34 |
35 | ## Install FastAPI
36 |
37 | The first step is to install FastAPI.
38 |
39 | For the tutorial, you might want to install it with all the optional dependencies and features:
40 |
41 |
42 |
43 | ```console
44 | $ pip install fastapi[all]
45 |
46 | ---> 100%
47 | ```
48 |
49 |
50 |
51 | ...that also includes `uvicorn`, that you can use as the server that runs your code.
52 |
53 | !!! note
54 | You can also install it part by part.
55 |
56 | This is what you would probably do once you want to deploy your application to production:
57 |
58 | ```
59 | pip install fastapi
60 | ```
61 |
62 | Also install `uvicorn` to work as the server:
63 |
64 | ```
65 | pip install uvicorn
66 | ```
67 |
68 | And the same for each of the optional dependencies that you want to use.
69 |
70 | ## Advanced User Guide
71 |
72 | There is also an **Advanced User Guide** that you can read later after this **Tutorial - User guide**.
73 |
74 | The **Advanced User Guide**, builds on this, uses the same concepts, and teaches you some extra features.
75 |
76 | But you should first read the **Tutorial - User guide** (what you are reading right now).
77 |
78 | It's designed so that you can build a complete application with just the **Tutorial - User guide**, and then extend it in different ways, depending on your needs, using some of the additional ideas from the **Advanced User Guide**.
79 |
--------------------------------------------------------------------------------
/tutorial/application-configuration.md:
--------------------------------------------------------------------------------
1 | There are several things that you can configure in your FastAPI application.
2 |
3 | ## Title, description, and version
4 |
5 | You can set the:
6 |
7 | * Title: used as your API's title/name, in OpenAPI and the automatic API docs UIs.
8 | * Description: the description of your API, in OpenAPI and the automatic API docs UIs.
9 | * Version: the version of your API, e.g. `v2` or `2.5.0`.
10 | * Useful for example if you had a previous version of the application, also using OpenAPI.
11 |
12 | To set them, use the parameters `title`, `description`, and `version`:
13 |
14 | ```Python hl_lines="4 5 6"
15 | {!./src/application_configuration/tutorial001.py!}
16 | ```
17 |
18 | With this configuration, the automatic API docs would look like:
19 |
20 |
21 |
22 | ## OpenAPI URL
23 |
24 | By default, the OpenAPI schema is served at `/openapi.json`.
25 |
26 | But you can configure it with the parameter `openapi_url`.
27 |
28 | For example, to set it to be served at `/api/v1/openapi.json`:
29 |
30 | ```Python hl_lines="3"
31 | {!./src/application_configuration/tutorial002.py!}
32 | ```
33 |
34 | If you want to disable the OpenAPI schema completely you can set `openapi_url=None`.
35 |
36 | ## Docs URLs
37 |
38 | You can configure the two documentation user interfaces included:
39 |
40 | * **Swagger UI**: served at `/docs`.
41 | * You can set its URL with the parameter `docs_url`.
42 | * You can disable it by setting `docs_url=None`.
43 | * ReDoc: served at `/redoc`.
44 | * You can set its URL with the parameter `redoc_url`.
45 | * You can disable it by setting `redoc_url=None`.
46 |
47 | For example, to set Swagger UI to be served at `/documentation` and disable ReDoc:
48 |
49 | ```Python hl_lines="3"
50 | {!./src/application_configuration/tutorial003.py!}
51 | ```
52 |
--------------------------------------------------------------------------------
/tutorial/body-fields.md:
--------------------------------------------------------------------------------
1 | The same way you can declare additional validation and metadata in *path operation function* parameters with `Query`, `Path` and `Body`, you can declare validation and metadata inside of Pydantic models using Pydantic's `Field`.
2 |
3 | ## Import `Field`
4 |
5 | First, you have to import it:
6 |
7 | ```Python hl_lines="2"
8 | {!./src/body_fields/tutorial001.py!}
9 | ```
10 |
11 | !!! warning
12 | Notice that `Field` is imported directly from `pydantic`, not from `fastapi` as are all the rest (`Query`, `Path`, `Body`, etc).
13 |
14 | ## Declare model attributes
15 |
16 | You can then use `Field` with model attributes:
17 |
18 | ```Python hl_lines="9 10"
19 | {!./src/body_fields/tutorial001.py!}
20 | ```
21 |
22 | `Field` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc.
23 |
24 | !!! note "Technical Details"
25 | Actually, `Query`, `Path` and others you'll see next create objects of subclasses of a common `Param` class, which is itself a subclass of Pydantic's `FieldInfo` class.
26 |
27 | And Pydantic's `Field` returns an instance of `FieldInfo` as well.
28 |
29 | `Body` also returns objects of a subclass of `FieldInfo` directly. And there are others you will see later that are subclasses of the `Body` class.
30 |
31 | Remember that when you import `Query`, `Path`, and others from `fastapi`, those are actually functions that return special classes.
32 |
33 | !!! tip
34 | Notice how each model's attribute with a type, default value and `Field` has the same structure as a *path operation function's* parameter, with `Field` instead of `Path`, `Query` and `Body`.
35 |
36 | ## JSON Schema extras
37 |
38 | In `Field`, `Path`, `Query`, `Body` and others you'll see later, you can declare extra parameters apart from those described before.
39 |
40 | Those parameters will be added as-is to the output JSON Schema.
41 |
42 | If you know JSON Schema and want to add extra information apart from what we have discussed here, you can pass that as extra keyword arguments.
43 |
44 | !!! warning
45 | Have in mind that extra parameters passed won't add any validation, only annotation, for documentation purposes.
46 |
47 | For example, you can use that functionality to pass a JSON Schema example field to a body request JSON Schema:
48 |
49 | ```Python hl_lines="20 21 22 23 24 25"
50 | {!./src/body_fields/tutorial002.py!}
51 | ```
52 |
53 | And it would look in the `/docs` like this:
54 |
55 |
56 |
57 | ## Recap
58 |
59 | You can use Pydantic's `Field` to declare extra validations and metadata for model attributes.
60 |
61 | You can also use the extra keyword arguments to pass additional JSON Schema metadata.
62 |
--------------------------------------------------------------------------------
/tutorial/cookie-params.md:
--------------------------------------------------------------------------------
1 | You can define Cookie parameters the same way you define `Query` and `Path` parameters.
2 |
3 | ## Import `Cookie`
4 |
5 | First import `Cookie`:
6 |
7 | ```Python hl_lines="1"
8 | {!./src/cookie_params/tutorial001.py!}
9 | ```
10 |
11 | ## Declare `Cookie` parameters
12 |
13 | Then declare the cookie parameters using the same structure as with `Path` and `Query`.
14 |
15 | The first value is the default value, you can pass all the extra validation or annotation parameters:
16 |
17 | ```Python hl_lines="7"
18 | {!./src/cookie_params/tutorial001.py!}
19 | ```
20 |
21 | !!! note "Technical Details"
22 | `Cookie` is a "sister" class of `Path` and `Query`. It also inherits from the same common `Param` class.
23 |
24 | But remember that when you import `Query`, `Path`, `Cookie` and others from `fastapi`, those are actually functions that return special classes.
25 |
26 | !!! info
27 | To declare cookies, you need to use `Cookie`, because otherwise the parameters would be interpreted as query parameters.
28 |
29 | ## Recap
30 |
31 | Declare cookies with `Cookie`, using the same common pattern as `Query` and `Path`.
32 |
--------------------------------------------------------------------------------
/tutorial/debugging.md:
--------------------------------------------------------------------------------
1 | You can connect the debugger in your editor, for example with Visual Studio Code or PyCharm.
2 |
3 | ## Call `uvicorn`
4 |
5 | In your FastAPI application, import and run `uvicorn` directly:
6 |
7 | ```Python hl_lines="1 15"
8 | {!./src/debugging/tutorial001.py!}
9 | ```
10 |
11 | ### About `__name__ == "__main__"`
12 |
13 | The main purpose of the `__name__ == "__main__"` is to have some code that is executed when your file is called with:
14 |
15 |
16 |
17 | ```console
18 | $ python myapp.py
19 | ```
20 |
21 |
22 |
23 | but is not called when another file imports it, like in:
24 |
25 | ```Python
26 | from myapp import app
27 | ```
28 |
29 | #### More details
30 |
31 | Let's say your file is named `myapp.py`.
32 |
33 | If you run it with:
34 |
35 |
36 |
37 | ```console
38 | $ python myapp.py
39 | ```
40 |
41 |
42 |
43 | then the internal variable `__name__` in your file, created automatically by Python, will have as value the string `"__main__"`.
44 |
45 | So, the section:
46 |
47 | ```Python
48 | uvicorn.run(app, host="0.0.0.0", port=8000)
49 | ```
50 |
51 | will run.
52 |
53 | ---
54 |
55 | This won't happen if you import that module (file).
56 |
57 | So, if you have another file `importer.py` with:
58 |
59 | ```Python
60 | from myapp import app
61 |
62 | # Some more code
63 | ```
64 |
65 | in that case, the automatic variable inside of `myapp.py` will not have the variable `__name__` with a value of `"__main__"`.
66 |
67 | So, the line:
68 |
69 | ```Python
70 | uvicorn.run(app, host="0.0.0.0", port=8000)
71 | ```
72 |
73 | will not be executed.
74 |
75 | !!! info
76 | For more information, check the official Python docs .
77 |
78 | ## Run your code with your debugger
79 |
80 | Because you are running the Uvicorn server directly from your code, you can call your Python program (your FastAPI application) directly from the debugger.
81 |
82 | ---
83 |
84 | For example, in Visual Studio Code, you can:
85 |
86 | * Go to the "Debug" panel.
87 | * "Add configuration...".
88 | * Select "Python"
89 | * Run the debugger with the option "`Python: Current File (Integrated Terminal)`".
90 |
91 | It will then start the server with your **FastAPI** code, stop at your breakpoints, etc.
92 |
93 | Here's how it might look:
94 |
95 |
96 |
--------------------------------------------------------------------------------
/tutorial/dependencies/dependencies-in-path-operation-decorators.md:
--------------------------------------------------------------------------------
1 | In some cases you don't really need the return value of a dependency inside your *path operation function*.
2 |
3 | Or the dependency doesn't return a value.
4 |
5 | But you still need it to be executed/solved.
6 |
7 | For those cases, instead of declaring a *path operation function* parameter with `Depends`, you can add a `list` of `dependencies` to the *path operation decorator*.
8 |
9 | ## Add `dependencies` to the *path operation decorator*
10 |
11 | The *path operation decorator* receives an optional argument `dependencies`.
12 |
13 | It should be a `list` of `Depends()`:
14 |
15 | ```Python hl_lines="17"
16 | {!./src/dependencies/tutorial006.py!}
17 | ```
18 |
19 | These dependencies will be executed/solved the same way normal dependencies. But their value (if they return any) won't be passed to your *path operation function*.
20 |
21 | !!! tip
22 | Some editors check for unused function parameters, and show them as errors.
23 |
24 | Using these `dependencies` in the *path operation decorator* you can make sure they are executed while avoiding editor/tooling errors.
25 |
26 | It might also help avoiding confusion for new developers that see an un-used parameter in your code and could think it's unnecessary.
27 |
28 | ## Dependencies errors and return values
29 |
30 | You can use the same dependency *functions* you use normally.
31 |
32 | ### Dependency requirements
33 |
34 | They can declare request requirements (like headers) or other sub-dependencies:
35 |
36 | ```Python hl_lines="6 11"
37 | {!./src/dependencies/tutorial006.py!}
38 | ```
39 |
40 | ### Raise exceptions
41 |
42 | These dependencies can `raise` exceptions, the same as normal dependencies:
43 |
44 | ```Python hl_lines="8 13"
45 | {!./src/dependencies/tutorial006.py!}
46 | ```
47 |
48 | ### Return values
49 |
50 | And they can return values or not, the values won't be used.
51 |
52 | So, you can re-use a normal dependency (that returns a value) you already use somewhere else, and even though the value won't be used, the dependency will be executed:
53 |
54 | ```Python hl_lines="9 14"
55 | {!./src/dependencies/tutorial006.py!}
56 | ```
57 |
58 | ## Dependencies for a group of *path operations*
59 |
60 | Later, when reading about how to structure bigger applications ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}), possibly with multiple files, you will learn how to declare a single `dependencies` parameter for a group of *path operations*.
61 |
--------------------------------------------------------------------------------
/tutorial/encoder.md:
--------------------------------------------------------------------------------
1 | There are some cases where you might need to convert a data type (like a Pydantic model) to something compatible with JSON (like a `dict`, `list`, etc).
2 |
3 | For example, if you need to store it in a database.
4 |
5 | For that, **FastAPI** provides a `jsonable_encoder()` function.
6 |
7 | ## Using the `jsonable_encoder`
8 |
9 | Let's imagine that you have a database `fake_db` that only receives JSON compatible data.
10 |
11 | For example, it doesn't receive `datetime` objects, as those are not compatible with JSON.
12 |
13 | So, a `datetime` object would have to be converted to a `str` containing the data in ISO format .
14 |
15 | The same way, this database wouldn't receive a Pydantic model (an object with attributes), only a `dict`.
16 |
17 | You can use `jsonable_encoder` for that.
18 |
19 | It receives an object, like a Pydantic model, and returns a JSON compatible version:
20 |
21 | ```Python hl_lines="4 21"
22 | {!./src/encoder/tutorial001.py!}
23 | ```
24 |
25 | In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`.
26 |
27 | The result of calling it is something that can be encoded with the Python standard `json.dumps()` .
28 |
29 | It doesn't return a large `str` containing the data in JSON format (as a string). It returns a Python standard data structure (e.g. a `dict`) with values and sub-values that are all compatible with JSON.
30 |
31 | !!! note
32 | `jsonable_encoder` is actually used by **FastAPI** internally to convert data. But it is useful in many other scenarios.
33 |
--------------------------------------------------------------------------------
/tutorial/extra-data-types.md:
--------------------------------------------------------------------------------
1 | Up to now, you have been using common data types, like:
2 |
3 | * `int`
4 | * `float`
5 | * `str`
6 | * `bool`
7 |
8 | But you can also use more complex data types.
9 |
10 | And you will still have the same features as seen up to now:
11 |
12 | * Great editor support.
13 | * Data conversion from incoming requests.
14 | * Data conversion for response data.
15 | * Data validation.
16 | * Automatic annotation and documentation.
17 |
18 | ## Other data types
19 |
20 | Here are some of the additional data types you can use:
21 |
22 | * `UUID`:
23 | * A standard "Universally Unique Identifier", common as an ID in many databases and systems.
24 | * In requests and responses will be represented as a `str`.
25 | * `datetime.datetime`:
26 | * A Python `datetime.datetime`.
27 | * In requests and responses will be represented as a `str` in ISO 8601 format, like: `2008-09-15T15:53:00+05:00`.
28 | * `datetime.date`:
29 | * Python `datetime.date`.
30 | * In requests and responses will be represented as a `str` in ISO 8601 format, like: `2008-09-15`.
31 | * `datetime.time`:
32 | * A Python `datetime.time`.
33 | * In requests and responses will be represented as a `str` in ISO 8601 format, like: `14:23:55.003`.
34 | * `datetime.timedelta`:
35 | * A Python `datetime.timedelta`.
36 | * In requests and responses will be represented as a `float` of total seconds.
37 | * Pydantic also allows representing it as a "ISO 8601 time diff encoding", see the docs for more info .
38 | * `frozenset`:
39 | * In requests and responses, treated the same as a `set`:
40 | * In requests, a list will be read, eliminating duplicates and converting it to a `set`.
41 | * In responses, the `set` will be converted to a `list`.
42 | * The generated schema will specify that the `set` values are unique (using JSON Schema's `uniqueItems`).
43 | * `bytes`:
44 | * Standard Python `bytes`.
45 | * In requests and responses will be treated as `str`.
46 | * The generated schema will specify that it's a `str` with `binary` "format".
47 | * `Decimal`:
48 | * Standard Python `Decimal`.
49 | * In requests and responses, handled the same as a `float`.
50 |
51 | ## Example
52 |
53 | Here's an example *path operation* with parameters using some of the above types.
54 |
55 | ```Python hl_lines="1 2 11 12 13 14 15"
56 | {!./src/extra_data_types/tutorial001.py!}
57 | ```
58 |
59 | Note that the parameters inside the function have their natural data type, and you can, for example, perform normal date manipulations, like:
60 |
61 | ```Python hl_lines="17 18"
62 | {!./src/extra_data_types/tutorial001.py!}
63 | ```
64 |
--------------------------------------------------------------------------------
/tutorial/request-forms-and-files.md:
--------------------------------------------------------------------------------
1 | You can define files and form fields at the same time using `File` and `Form`.
2 |
3 | !!! info
4 | To receive uploaded files and/or form data, first install `python-multipart` .
5 |
6 | E.g. `pip install python-multipart`.
7 |
8 | ## Import `File` and `Form`
9 |
10 | ```Python hl_lines="1"
11 | {!./src/request_forms_and_files/tutorial001.py!}
12 | ```
13 |
14 | ## Define `File` and `Form` parameters
15 |
16 | Create file and form parameters the same way you would for `Body` or `Query`:
17 |
18 | ```Python hl_lines="8"
19 | {!./src/request_forms_and_files/tutorial001.py!}
20 | ```
21 |
22 | The files and form fields will be uploaded as form data and you will receive the files and form fields.
23 |
24 | And you can declare some of the files as `bytes` and some as `UploadFile`.
25 |
26 | !!! warning
27 | You can declare multiple `File` and `Form` parameters in a *path operation*, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
28 |
29 | This is not a limitation of **FastAPI**, it's part of the HTTP protocol.
30 |
31 | ## Recap
32 |
33 | Use `File` and `Form` together when you need to receive data and files in the same request.
34 |
--------------------------------------------------------------------------------
/tutorial/request-forms.md:
--------------------------------------------------------------------------------
1 | When you need to receive form fields instead of JSON, you can use `Form`.
2 |
3 | !!! info
4 | To use forms, first install `python-multipart` .
5 |
6 | E.g. `pip install python-multipart`.
7 |
8 | ## Import `Form`
9 |
10 | Import `Form` from `fastapi`:
11 |
12 | ```Python hl_lines="1"
13 | {!./src/request_forms/tutorial001.py!}
14 | ```
15 |
16 | ## Define `Form` parameters
17 |
18 | Create form parameters the same way you would for `Body` or `Query`:
19 |
20 | ```Python hl_lines="7"
21 | {!./src/request_forms/tutorial001.py!}
22 | ```
23 |
24 | For example, in one of the ways the OAuth2 specification can be used (called "password flow") it is required to send a `username` and `password` as form fields.
25 |
26 | The spec requires the fields to be exactly named `username` and `password`, and to be sent as form fields, not JSON.
27 |
28 | With `Form` you can declare the same metadata and validation as with `Body` (and `Query`, `Path`, `Cookie`).
29 |
30 | !!! info
31 | `Form` is a class that inherits directly from `Body`.
32 |
33 | !!! tip
34 | To declare form bodies, you need to use `Form` explicitly, because without it the parameters would be interpreted as query parameters or body (JSON) parameters.
35 |
36 | ## About "Form Fields"
37 |
38 | The way HTML forms (``) sends the data to the server normally uses a "special" encoding for that data, it's different from JSON.
39 |
40 | **FastAPI** will make sure to read that data from the right place instead of JSON.
41 |
42 | !!! note "Technical Details"
43 | Data from forms is normally encoded using the "media type" `application/x-www-form-urlencoded`.
44 |
45 | But when the form includes files, it is encoded as `multipart/form-data`. You'll read about handling files in the next chapter.
46 |
47 | If you want to read more about these encodings and form fields, head to the MDN web docs for POST
.
48 |
49 | !!! warning
50 | You can declare multiple `Form` parameters in a *path operation*, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `application/x-www-form-urlencoded` instead of `application/json`.
51 |
52 | This is not a limitation of **FastAPI**, it's part of the HTTP protocol.
53 |
54 | ## Recap
55 |
56 | Use `Form` to declare form data input parameters.
57 |
--------------------------------------------------------------------------------
/tutorial/static-files.md:
--------------------------------------------------------------------------------
1 | You can serve static files automatically from a directory using `StaticFiles`.
2 |
3 | ## Install `aiofiles`
4 |
5 | First you need to install `aiofiles`:
6 |
7 |
8 |
9 | ```console
10 | $ pip install aiofiles
11 |
12 | ---> 100%
13 | ```
14 |
15 |
16 |
17 | ## Use `StaticFiles`
18 |
19 | * Import `StaticFiles`.
20 | * "Mount" a `StaticFiles()` instance in a specific path.
21 |
22 | ```Python hl_lines="2 6"
23 | {!./src/static_files/tutorial001.py!}
24 | ```
25 |
26 | !!! note "Technical Details"
27 | You could also use `from starlette.staticfiles import StaticFiles`.
28 |
29 | **FastAPI** provides the same `starlette.staticfiles` as `fastapi.staticfiles` just as a convenience for you, the developer. But it actually comes directly from Starlette.
30 |
31 | ### What is "Mounting"
32 |
33 | "Mounting" means adding a complete "independent" application in a specific path, that then takes care of handling all the sub-paths.
34 |
35 | This is different from using an `APIRouter` as a mounted application is completely independent. The OpenAPI and docs from your main application won't include anything from the mounted application, etc.
36 |
37 | You can read more about this in the **Advanced User Guide**.
38 |
39 | ## Details
40 |
41 | The first `"/static"` refers to the sub-path this "sub-application" will be "mounted" on. So, any path that starts with `"/static"` will be handled by it.
42 |
43 | The `directory="static"` refers to the name of the directory that contains your static files.
44 |
45 | The `name="static"` gives it a name that can be used internally by **FastAPI**.
46 |
47 | All these parameters can be different than "`static`", adjust them with the needs and specific details of your own application.
48 |
49 | ## More info
50 |
51 | For more details and options check Starlette's docs about Static Files .
52 |
--------------------------------------------------------------------------------