├── .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 |
24 | 25 | 26 |
27 |
28 | 29 | 30 |
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 |
15 | 16 | 17 |
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 |
15 | 16 | 17 |
18 | 19 | 20 |
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 | --------------------------------------------------------------------------------