mirror of
https://github.com/fastapi/fastapi.git
synced 2026-05-18 21:39:22 -04:00
📝 Move tutorial src files to top level docs
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
Coming soon...
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/application-configuration/tutorial001.py!}
|
||||
{!./src/application-configuration/tutorial001.py!}
|
||||
```
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/application-configuration/tutorial002.py!}
|
||||
{!./src/application-configuration/tutorial002.py!}
|
||||
```
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/application-configuration/tutorial003.py!}
|
||||
{!./src/application-configuration/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
Coming soon...
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/bigger_applications/app/routers/tutorial001.py!}
|
||||
{!./src/bigger_applications/app/routers/tutorial001.py!}
|
||||
```
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/bigger_applications/app/routers/tutorial002.py!}
|
||||
{!./src/bigger_applications/app/routers/tutorial002.py!}
|
||||
```
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/bigger_applications/app/tutorial003.py!}
|
||||
{!./src/bigger_applications/app/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@ First, of course, you can mix `Path`, `Query` and request body parameter declara
|
||||
And you can also declare body parameters as optional, by setting the default to `None`:
|
||||
|
||||
```Python hl_lines="17 18 19"
|
||||
{!./tutorial/src/body_multiple_params/tutorial001.py!}
|
||||
{!./src/body_multiple_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -30,7 +30,7 @@ In the previous example, the path operations would expect a JSON body with the a
|
||||
But you can also declare multiple body parameters, e.g. `item` and `user`:
|
||||
|
||||
```Python hl_lines="20"
|
||||
{!./tutorial/src/body_multiple_params/tutorial002.py!}
|
||||
{!./src/body_multiple_params/tutorial002.py!}
|
||||
```
|
||||
|
||||
In this case, **FastAPI** will notice that there are more than one body parameter in the function (two parameters that are Pydantic models).
|
||||
@@ -72,7 +72,7 @@ But you can instruct **FastAPI** to treat it as another body key using `Body`:
|
||||
|
||||
|
||||
```Python hl_lines="21"
|
||||
{!./tutorial/src/body_multiple_params/tutorial003.py!}
|
||||
{!./src/body_multiple_params/tutorial003.py!}
|
||||
```
|
||||
|
||||
In this case, **FastAPI** will expect a body like:
|
||||
@@ -109,7 +109,7 @@ q: str = None
|
||||
as in:
|
||||
|
||||
```Python hl_lines="25"
|
||||
{!./tutorial/src/body_multiple_params/tutorial004.py!}
|
||||
{!./src/body_multiple_params/tutorial004.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
@@ -131,7 +131,7 @@ item: Item = Body(..., embed=True)
|
||||
as in:
|
||||
|
||||
```Python hl_lines="15"
|
||||
{!./tutorial/src/body_multiple_params/tutorial005.py!}
|
||||
{!./src/body_multiple_params/tutorial005.py!}
|
||||
```
|
||||
|
||||
In this case **FastAPI** will expect a body like:
|
||||
|
||||
@@ -5,7 +5,7 @@ With **FastAPI**, you can define, validate, document, and use arbitrarily deeply
|
||||
You can define an attribute to be a subtype. For example, a Python `list`:
|
||||
|
||||
```Python hl_lines="12"
|
||||
{!./tutorial/src/body_nested_models/tutorial001.py!}
|
||||
{!./src/body_nested_models/tutorial001.py!}
|
||||
```
|
||||
|
||||
This will make `tags` be a list of items. Although it doesn't declare the type of each of the items.
|
||||
@@ -19,7 +19,7 @@ But Python has a specific way to declare lists with subtypes:
|
||||
First, import `List` from standard Python's `typing` module:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/body_nested_models/tutorial002.py!}
|
||||
{!./src/body_nested_models/tutorial002.py!}
|
||||
```
|
||||
|
||||
### Declare a `List` with a subtype
|
||||
@@ -42,7 +42,7 @@ Use that same standard syntax for model attributes with subtypes.
|
||||
So, in our example, we can make `tags` be specifically a "list of strings":
|
||||
|
||||
```Python hl_lines="14"
|
||||
{!./tutorial/src/body_nested_models/tutorial002.py!}
|
||||
{!./src/body_nested_models/tutorial002.py!}
|
||||
```
|
||||
|
||||
## Set types
|
||||
@@ -54,7 +54,7 @@ And Python has a special data type for sets of unique items, the `set`.
|
||||
Then we can import `Set` and declare `tags` as a `set` of `str`:
|
||||
|
||||
```Python hl_lines="1 14"
|
||||
{!./tutorial/src/body_nested_models/tutorial003.py!}
|
||||
{!./src/body_nested_models/tutorial003.py!}
|
||||
```
|
||||
|
||||
With this, even if you receive a request with duplicate data, it will be converted to a set of unique items.
|
||||
@@ -78,7 +78,7 @@ All that, arbitrarily nested.
|
||||
For example, we can define an `Image` model:
|
||||
|
||||
```Python hl_lines="9 10 11"
|
||||
{!./tutorial/src/body_nested_models/tutorial004.py!}
|
||||
{!./src/body_nested_models/tutorial004.py!}
|
||||
```
|
||||
|
||||
### Use the submodel as a type
|
||||
@@ -86,7 +86,7 @@ For example, we can define an `Image` model:
|
||||
And then we can use it as the type of an attribute:
|
||||
|
||||
```Python hl_lines="20"
|
||||
{!./tutorial/src/body_nested_models/tutorial004.py!}
|
||||
{!./src/body_nested_models/tutorial004.py!}
|
||||
```
|
||||
|
||||
This would mean that **FastAPI** would expect a body similar to:
|
||||
@@ -121,7 +121,7 @@ To see all the options you have, checkout the docs for <a href="https://pydantic
|
||||
For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `UrlStr`:
|
||||
|
||||
```Python hl_lines="5 11"
|
||||
{!./tutorial/src/body_nested_models/tutorial005.py!}
|
||||
{!./src/body_nested_models/tutorial005.py!}
|
||||
```
|
||||
|
||||
The string will be checked to be a valid URL, and documented in JSON Schema / OpenAPI as such.
|
||||
@@ -131,7 +131,7 @@ The string will be checked to be a valid URL, and documented in JSON Schema / Op
|
||||
You can also use Pydantic models as subtypes of `list`, `set`, etc:
|
||||
|
||||
```Python hl_lines="21"
|
||||
{!./tutorial/src/body_nested_models/tutorial006.py!}
|
||||
{!./src/body_nested_models/tutorial006.py!}
|
||||
```
|
||||
|
||||
This will expect (convert, validate, document, etc) a JSON body like:
|
||||
@@ -168,7 +168,7 @@ This will expect (convert, validate, document, etc) a JSON body like:
|
||||
You can define arbitrarily deeply nested models:
|
||||
|
||||
```Python hl_lines="10 15 21 24 28"
|
||||
{!./tutorial/src/body_nested_models/tutorial007.py!}
|
||||
{!./src/body_nested_models/tutorial007.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
@@ -185,7 +185,7 @@ images: List[Image]
|
||||
as in:
|
||||
|
||||
```Python hl_lines="16"
|
||||
{!./tutorial/src/body_nested_models/tutorial008.py!}
|
||||
{!./src/body_nested_models/tutorial008.py!}
|
||||
```
|
||||
|
||||
## Editor support everywhere
|
||||
|
||||
@@ -5,7 +5,7 @@ The same way you can declare additional validation and metadata in path operatio
|
||||
First, you have to import it:
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!./tutorial/src/body_schema/tutorial001.py!}
|
||||
{!./src/body_schema/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! warning
|
||||
@@ -17,7 +17,7 @@ First, you have to import it:
|
||||
You can then use `Schema` with model attributes:
|
||||
|
||||
```Python hl_lines="9 10"
|
||||
{!./tutorial/src/body_schema/tutorial001.py!}
|
||||
{!./src/body_schema/tutorial001.py!}
|
||||
```
|
||||
|
||||
`Schema` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc.
|
||||
@@ -45,7 +45,7 @@ If you know JSON Schema and want to add extra information appart from what we ha
|
||||
For example, you can use that functionality to pass a <a href="http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.5" target="_blank">JSON Schema example</a> field to a body request JSON Schema:
|
||||
|
||||
```Python hl_lines="20 21 22 23 24 25"
|
||||
{!./tutorial/src/body_schema/tutorial002.py!}
|
||||
{!./src/body_schema/tutorial002.py!}
|
||||
```
|
||||
|
||||
## Recap
|
||||
|
||||
@@ -5,7 +5,7 @@ To declare a request body, you use <a href="https://pydantic-docs.helpmanual.io/
|
||||
First, you need to import `BaseModel` from `pydantic`:
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!./tutorial/src/body/tutorial001.py!}
|
||||
{!./src/body/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Create your data model
|
||||
@@ -15,7 +15,7 @@ Then you declare your data model as a class that inherits from `BaseModel`.
|
||||
Use standard Python types for all the attributes:
|
||||
|
||||
```Python hl_lines="5 6 7 8 9"
|
||||
{!./tutorial/src/body/tutorial001.py!}
|
||||
{!./src/body/tutorial001.py!}
|
||||
```
|
||||
|
||||
The same as when declaring query parameters, when a model attribute has a default value, it is not required. Otherwise, it is required. Use `None` to make it just optional.
|
||||
@@ -45,7 +45,7 @@ For example, this model above declares a JSON "`object`" (or Python `dict`) like
|
||||
To add it to your path operation, declare it the same way you declared path and query parameters:
|
||||
|
||||
```Python hl_lines="16"
|
||||
{!./tutorial/src/body/tutorial001.py!}
|
||||
{!./src/body/tutorial001.py!}
|
||||
```
|
||||
|
||||
...and declare its type as the model you created, `Item`.
|
||||
@@ -101,7 +101,7 @@ But you would get the same editor support with <a href="https://www.jetbrains.co
|
||||
Inside of the function, you can access all the attributes of the model object directly:
|
||||
|
||||
```Python hl_lines="19"
|
||||
{!./tutorial/src/body/tutorial002.py!}
|
||||
{!./src/body/tutorial002.py!}
|
||||
```
|
||||
|
||||
## Request body + path parameters
|
||||
@@ -111,7 +111,7 @@ You can declare path parameters and body requests at the same time.
|
||||
**FastAPI** will recognize that the function parameters that match path parameters should be **taken from the path**, and that function parameters that are declared to be Pydantic models should be **taken from the request body**.
|
||||
|
||||
```Python hl_lines="15 16"
|
||||
{!./tutorial/src/body/tutorial003.py!}
|
||||
{!./src/body/tutorial003.py!}
|
||||
```
|
||||
|
||||
## Request body + path + query parameters
|
||||
@@ -121,7 +121,7 @@ You can also declare **body**, **path** and **query** parameters, all at the sam
|
||||
**FastAPI** will recognize each of them and take the data from the correct place.
|
||||
|
||||
```Python hl_lines="16"
|
||||
{!./tutorial/src/body/tutorial004.py!}
|
||||
{!./src/body/tutorial004.py!}
|
||||
```
|
||||
|
||||
The function parameters will be recognized as follows:
|
||||
|
||||
@@ -5,7 +5,7 @@ You can define Cookie parameters the same way you define `Query` and `Path` para
|
||||
First import `Cookie`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/cookie_params/tutorial001.py!}
|
||||
{!./src/cookie_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Declare `Cookie` parameteres
|
||||
@@ -15,7 +15,7 @@ Then declare the cookie parameters using the same structure as with `Path` and `
|
||||
The first value is the default value, you can pass all the extra validation or annotation parameteres:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/cookie_params/tutorial001.py!}
|
||||
{!./src/cookie_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
|
||||
@@ -14,7 +14,7 @@ For example, if you are squeezing performance, you can use `ujson` and set the r
|
||||
### Import `UJSONResponse`
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!./tutorial/src/custom_response/tutorial001.py!}
|
||||
{!./src/custom_response/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -25,7 +25,7 @@ For example, if you are squeezing performance, you can use `ujson` and set the r
|
||||
Make your path operation use `UJSONResponse` as the response class using the parameter `content_type`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/custom_response/tutorial001.py!}
|
||||
{!./src/custom_response/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
@@ -40,7 +40,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
|
||||
### Import `HTMLResponse`
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!./tutorial/src/custom_response/tutorial002.py!}
|
||||
{!./src/custom_response/tutorial002.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -52,7 +52,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
|
||||
Pass `HTMLResponse` as the parameter `content_type` of your path operation:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/custom_response/tutorial002.py!}
|
||||
{!./src/custom_response/tutorial002.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
@@ -72,7 +72,7 @@ If you return an object that is an instance of Starlette's `Response`, it will b
|
||||
The same example from above, returning an `HTMLResponse`, could look like:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/custom_response/tutorial003.py!}
|
||||
{!./src/custom_response/tutorial003.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
@@ -93,7 +93,7 @@ The `content_type` class will then be used only to document the OpenAPI path ope
|
||||
For example, it could be something like:
|
||||
|
||||
```Python hl_lines="7 23"
|
||||
{!./tutorial/src/custom_response/tutorial004.py!}
|
||||
{!./src/custom_response/tutorial004.py!}
|
||||
```
|
||||
|
||||
In this example, the function `generate_html_response()` already generates a Starlette `Response` instead of the HTML in a `str`.
|
||||
@@ -105,7 +105,7 @@ By returning the result of calling `generate_html_response()`, you are already r
|
||||
But by declaring it also in the path operation decorator:
|
||||
|
||||
```Python hl_lines="21"
|
||||
{!./tutorial/src/custom_response/tutorial004.py!}
|
||||
{!./src/custom_response/tutorial004.py!}
|
||||
```
|
||||
|
||||
#### OpenAPI knows how to document it
|
||||
|
||||
@@ -13,7 +13,7 @@ Let's first focus on the dependency.
|
||||
It is just a function that can take all the same parameters that a path operation function can take:
|
||||
|
||||
```Python hl_lines="6 7"
|
||||
{!./tutorial/src/dependencies/tutorial001.py!}
|
||||
{!./src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
That's it.
|
||||
@@ -37,7 +37,7 @@ And then it just returns a `dict` containing those values.
|
||||
## Import `Depends`
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/dependencies/tutorial001.py!}
|
||||
{!./src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Declare the dependency, in the "dependant"
|
||||
@@ -45,7 +45,7 @@ And then it just returns a `dict` containing those values.
|
||||
The same way you use `Body`, `Query`, etc. with your path operation function parameters, use `Depends` with a new parameter:
|
||||
|
||||
```Python hl_lines="11"
|
||||
{!./tutorial/src/dependencies/tutorial001.py!}
|
||||
{!./src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
Although you use it in the parameters of your function too, `Depends` works a bit differently.
|
||||
|
||||
@@ -5,7 +5,7 @@ Before diving deeper into the **Dependency Injection** system, let's upgrade the
|
||||
In the previous example, we where returning a `dict` from our dependency ("dependable"):
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/dependencies/tutorial001.py!}
|
||||
{!./src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
But then we get a `dict` in the parameter `commons` of the path operation function.
|
||||
@@ -21,7 +21,7 @@ Let's use them here too.
|
||||
Create a model for the common parameters (and don't pay attention to the rest, for now):
|
||||
|
||||
```Python hl_lines="11 12 13 14"
|
||||
{!./tutorial/src/dependencies/tutorial002.py!}
|
||||
{!./src/dependencies/tutorial002.py!}
|
||||
```
|
||||
|
||||
## Return a Pydantic model
|
||||
@@ -29,7 +29,7 @@ Create a model for the common parameters (and don't pay attention to the rest, f
|
||||
Now we can return a Pydantic model from the dependency ("dependable") with the same data as the dict before:
|
||||
|
||||
```Python hl_lines="18"
|
||||
{!./tutorial/src/dependencies/tutorial002.py!}
|
||||
{!./src/dependencies/tutorial002.py!}
|
||||
```
|
||||
|
||||
## Declare the Pydantic model
|
||||
@@ -43,7 +43,7 @@ commons: CommonQueryParams = Depends(common_parameters)
|
||||
It won't be interpreted as a JSON request `Body` because we are using `Depends`:
|
||||
|
||||
```Python hl_lines="22"
|
||||
{!./tutorial/src/dependencies/tutorial002.py!}
|
||||
{!./src/dependencies/tutorial002.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
@@ -56,7 +56,7 @@ It won't be interpreted as a JSON request `Body` because we are using `Depends`:
|
||||
And now we can use that model in our code, with all the lovable editor support:
|
||||
|
||||
```Python hl_lines="24 25 26"
|
||||
{!./tutorial/src/dependencies/tutorial002.py!}
|
||||
{!./src/dependencies/tutorial002.py!}
|
||||
```
|
||||
|
||||
<img src="/img/tutorial/dependencies/image02.png">
|
||||
|
||||
@@ -14,7 +14,7 @@ This is especially the case for user models, because:
|
||||
Here's a general idea of how the models could look like with their password fields and the places where they are used:
|
||||
|
||||
```Python hl_lines="8 10 15 21 23 32 34 39 40"
|
||||
{!./tutorial/src/extra_models/tutorial001.py!}
|
||||
{!./src/extra_models/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! warning
|
||||
@@ -37,7 +37,7 @@ All the data conversion, validation, documentation, etc. will still work as norm
|
||||
That way, we can declare just the differences between the models (with plaintext `password`, with `hashed_password` and without password):
|
||||
|
||||
```Python hl_lines="8 14 15 18 19 22 23"
|
||||
{!./tutorial/src/extra_models/tutorial002.py!}
|
||||
{!./src/extra_models/tutorial002.py!}
|
||||
```
|
||||
|
||||
## Recap
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
The simplest FastAPI file could look like this:
|
||||
|
||||
```Python
|
||||
{!tutorial/src/first_steps/tutorial001.py!}
|
||||
{!./src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
Copy that to a file `main.py`.
|
||||
@@ -89,7 +89,7 @@ It will show a JSON starting with something like:
|
||||
### Step 1: import `FastAPI`
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!tutorial/src/first_steps/tutorial001.py!}
|
||||
{!./src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
`FastAPI` is a Python class that provides all the functionality for your API.
|
||||
@@ -102,7 +102,7 @@ It will show a JSON starting with something like:
|
||||
### Step 2: create a `FastAPI` "instance"
|
||||
|
||||
```Python hl_lines="3"
|
||||
{!tutorial/src/first_steps/tutorial001.py!}
|
||||
{!./src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
Here the `app` variable will be an "instance" of the class `FastAPI`.
|
||||
@@ -118,7 +118,7 @@ uvicorn main:app --debug
|
||||
If you create your app like:
|
||||
|
||||
```Python hl_lines="3"
|
||||
{!tutorial/src/first_steps/tutorial002.py!}
|
||||
{!./src/first_steps/tutorial002.py!}
|
||||
```
|
||||
|
||||
And put it in a file `main.py`, then you would call `uvicorn` like:
|
||||
@@ -188,7 +188,7 @@ We are going to call them "operations" too.
|
||||
#### Define a path operation function
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!tutorial/src/first_steps/tutorial001.py!}
|
||||
{!./src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
The `@app.get("/")` tells **FastAPI** that the function right below is in charge of handling requests that go to:
|
||||
@@ -221,7 +221,7 @@ And the more exotic ones:
|
||||
### Step 4: define the path operation function
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!tutorial/src/first_steps/tutorial001.py!}
|
||||
{!./src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
This is a Python function.
|
||||
@@ -235,7 +235,7 @@ In this case, it is an `async` function.
|
||||
You could also define it as a normal function instead of `async def`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!tutorial/src/first_steps/tutorial003.py!}
|
||||
{!./src/first_steps/tutorial003.py!}
|
||||
```
|
||||
|
||||
To know the difference, read the section about [Concurrency and `async` / `await`](/async/).
|
||||
@@ -243,7 +243,7 @@ To know the difference, read the section about [Concurrency and `async` / `await
|
||||
### Step 5: return the content
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!tutorial/src/first_steps/tutorial001.py!}
|
||||
{!./src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
You can return a `dict`, `list`, singular values as `str`, `int`, etc.
|
||||
|
||||
@@ -5,7 +5,7 @@ You can define Header parameters the same way you define `Query`, `Path` and `Co
|
||||
First import `Header`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/header_params/tutorial001.py!}
|
||||
{!./src/header_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Declare `Header` parameteres
|
||||
@@ -15,7 +15,7 @@ Then declare the header parameters using the same structure as with `Path`, `Que
|
||||
The first value is the default value, you can pass all the extra validation or annotation parameteres:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/header_params/tutorial001.py!}
|
||||
{!./src/header_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
@@ -41,7 +41,7 @@ So, you can use `user_agent` as you normally would in Python code, instead of ne
|
||||
If for some reason you need to disable automatic conversion of underscores to hyphens, set the parameter `convert_underscores` of `Header` to `False`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/header_params/tutorial002.py!}
|
||||
{!./src/header_params/tutorial002.py!}
|
||||
```
|
||||
|
||||
!!! warning
|
||||
|
||||
@@ -15,7 +15,7 @@ You can adapt it to any other NoSQL database like:
|
||||
For now, don't pay attention to the rest, only the imports:
|
||||
|
||||
```Python hl_lines="6 7 8"
|
||||
{!./tutorial/src/nosql_databases/tutorial001.py!}
|
||||
{!./src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Define a constant to use as a "document type"
|
||||
@@ -25,7 +25,7 @@ We will use it later as a fixed field `type` in our documents.
|
||||
This is not required by Couchbase, but is a good practice that will help you afterwards.
|
||||
|
||||
```Python hl_lines="10"
|
||||
{!./tutorial/src/nosql_databases/tutorial001.py!}
|
||||
{!./src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Add a function to get a `Bucket`
|
||||
@@ -50,7 +50,7 @@ This utility function will:
|
||||
* Return it.
|
||||
|
||||
```Python hl_lines="13 14 15 16 17 18 19 20"
|
||||
{!./tutorial/src/nosql_databases/tutorial001.py!}
|
||||
{!./src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Create Pydantic models
|
||||
@@ -62,7 +62,7 @@ As **Couchbase** "documents" are actually just "JSON objects", we can model them
|
||||
First, let's create a `User` model:
|
||||
|
||||
```Python hl_lines="23 24 25 26 27"
|
||||
{!./tutorial/src/nosql_databases/tutorial001.py!}
|
||||
{!./src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
We will use this model in our path operation function, so, we don't include in it the `hashed_password`.
|
||||
@@ -76,7 +76,7 @@ This will have the data that is actually stored in the database.
|
||||
We don't create it as a subclass of Pydantic's `BaseModel` but as a subclass of our own `User`, because it will have all the attributes in `User` plus a couple more:
|
||||
|
||||
```Python hl_lines="30 31 32"
|
||||
{!./tutorial/src/nosql_databases/tutorial001.py!}
|
||||
{!./src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -97,7 +97,7 @@ Now create a function that will:
|
||||
By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your path operation function, you can more easily re-use it in multiple parts and also add <abbr title="Automated test, written in code, that checks if another piece of code is working correctly.">unit tests</abbr> for it:
|
||||
|
||||
```Python hl_lines="35 36 37 38 39 40 41"
|
||||
{!./tutorial/src/nosql_databases/tutorial001.py!}
|
||||
{!./src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
### f-strings
|
||||
@@ -132,7 +132,7 @@ UserInDB(username="johndoe", hashed_password="some_hash")
|
||||
### Create the `FastAPI` app
|
||||
|
||||
```Python hl_lines="45"
|
||||
{!./tutorial/src/nosql_databases/tutorial001.py!}
|
||||
{!./src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Create the path operation function
|
||||
@@ -142,7 +142,7 @@ As our code is calling Couchbase and we are not using the <a href="https://docs.
|
||||
Also, Couchbase recommends not using a single `Bucket` object in multiple "<abbr title="A sequence of code being executed by the program, while at the same time, or at intervals, there can be others being executed too.">thread</abbr>s", so, we can get just get the bucket directly and pass it to our utility functions:
|
||||
|
||||
```Python hl_lines="48 49 50 51 52"
|
||||
{!./tutorial/src/nosql_databases/tutorial001.py!}
|
||||
{!./src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Recap
|
||||
|
||||
@@ -8,7 +8,7 @@ You can set the OpenAPI `operationId` to be used in your path operation with the
|
||||
You would have to make sure that it is unique for each operation.
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!./tutorial/src/path_operation_advanced_configuration/tutorial001.py!}
|
||||
{!./src/path_operation_advanced_configuration/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Exclude from OpenAPI
|
||||
@@ -16,5 +16,5 @@ You would have to make sure that it is unique for each operation.
|
||||
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`;
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!./tutorial/src/path_operation_advanced_configuration/tutorial002.py!}
|
||||
{!./src/path_operation_advanced_configuration/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -12,7 +12,7 @@ You can pass directly the `int` code, like `404`.
|
||||
But if you don't remember what each number code is for, you can use the shortcut constants from `starlette`:
|
||||
|
||||
```Python hl_lines="5 18"
|
||||
{!./tutorial/src/path_operation_configuration/tutorial001.py!}
|
||||
{!./src/path_operation_configuration/tutorial001.py!}
|
||||
```
|
||||
|
||||
That status code will be used in the response and will be added to the OpenAPI schema.
|
||||
@@ -23,7 +23,7 @@ That status code will be used in the response and will be added to the OpenAPI s
|
||||
You can add tags to your path operation, pass the parameter `tags` with a `list` of `str` (commonly just one `str`):
|
||||
|
||||
```Python hl_lines="17 22 27"
|
||||
{!./tutorial/src/path_operation_configuration/tutorial002.py!}
|
||||
{!./src/path_operation_configuration/tutorial002.py!}
|
||||
```
|
||||
|
||||
They will be added to the OpenAPI schema and used by the automatic documentation interfaces:
|
||||
@@ -35,7 +35,7 @@ They will be added to the OpenAPI schema and used by the automatic documentation
|
||||
You can add a `summary` and `description`:
|
||||
|
||||
```Python hl_lines="20 21"
|
||||
{!./tutorial/src/path_operation_configuration/tutorial003.py!}
|
||||
{!./src/path_operation_configuration/tutorial003.py!}
|
||||
```
|
||||
|
||||
## Description from docstring
|
||||
@@ -43,7 +43,7 @@ You can add a `summary` and `description`:
|
||||
As descriptions tend to be long and cover multiple lines, you can declare the path operation description in the function <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr> and **FastAPI** will read it from there.
|
||||
|
||||
```Python hl_lines="19 20 21 22 23 24 25 26 27"
|
||||
{!./tutorial/src/path_operation_configuration/tutorial004.py!}
|
||||
{!./src/path_operation_configuration/tutorial004.py!}
|
||||
```
|
||||
|
||||
It will be used in the interactive docs:
|
||||
@@ -58,7 +58,7 @@ It will be used in the interactive docs:
|
||||
You can specify the response description with the parameter `response_description`:
|
||||
|
||||
```Python hl_lines="21"
|
||||
{!./tutorial/src/path_operation_configuration/tutorial005.py!}
|
||||
{!./src/path_operation_configuration/tutorial005.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
@@ -77,7 +77,7 @@ If you need to mark a path operation as <abbr title="obsolete, recommended not t
|
||||
|
||||
|
||||
```Python hl_lines="16"
|
||||
{!./tutorial/src/path_operation_configuration/tutorial006.py!}
|
||||
{!./src/path_operation_configuration/tutorial006.py!}
|
||||
```
|
||||
|
||||
It will be clearly marked as deprecated in the interactive docs:
|
||||
|
||||
@@ -5,7 +5,7 @@ The same way you can declare more validations and metadata for query parameters
|
||||
First, import `Path` from `fastapi`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/path_params_numeric_validations/tutorial001.py!}
|
||||
{!./src/path_params_numeric_validations/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Declare metadata
|
||||
@@ -15,7 +15,7 @@ You can declare all the same parameters as for `Query`.
|
||||
For example, to declare a `title` metadata value for the path parameter `item_id` you can type:
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!./tutorial/src/path_params_numeric_validations/tutorial001.py!}
|
||||
{!./src/path_params_numeric_validations/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -42,7 +42,7 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names,
|
||||
So, you can declare your function as:
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!./tutorial/src/path_params_numeric_validations/tutorial002.py!}
|
||||
{!./src/path_params_numeric_validations/tutorial002.py!}
|
||||
```
|
||||
|
||||
## Order the parameters as you need, tricks
|
||||
@@ -54,7 +54,7 @@ Pass `*`, as the first parameter of the function.
|
||||
Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Even if they don't have a default value.
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!./tutorial/src/path_params_numeric_validations/tutorial003.py!}
|
||||
{!./src/path_params_numeric_validations/tutorial003.py!}
|
||||
```
|
||||
|
||||
## Number validations: greater than or equal
|
||||
@@ -64,7 +64,7 @@ With `Query` and `Path` (and other's you'll see later) you can declare string co
|
||||
Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than or `e`qual" to `1`.
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!./tutorial/src/path_params_numeric_validations/tutorial004.py!}
|
||||
{!./src/path_params_numeric_validations/tutorial004.py!}
|
||||
```
|
||||
## Number validations: greater than and less than or equal
|
||||
|
||||
@@ -74,7 +74,7 @@ The same applies for:
|
||||
* `le`: `l`ess than or `e`qual
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!./tutorial/src/path_params_numeric_validations/tutorial005.py!}
|
||||
{!./src/path_params_numeric_validations/tutorial005.py!}
|
||||
```
|
||||
|
||||
## Number validations: floats, greater than and less than
|
||||
@@ -88,7 +88,7 @@ So, `0.5` would be a valid value. But `0.0` or `0` would not.
|
||||
And the same for <abbr title="less than"><code>lt</code></abbr>.
|
||||
|
||||
```Python hl_lines="11"
|
||||
{!./tutorial/src/path_params_numeric_validations/tutorial006.py!}
|
||||
{!./src/path_params_numeric_validations/tutorial006.py!}
|
||||
```
|
||||
|
||||
## Recap
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
You can declare path "parameters" or "variables" with the same syntax used by Python format strings:
|
||||
|
||||
```Python hl_lines="6 7"
|
||||
{!./tutorial/src/path_params/tutorial001.py!}
|
||||
{!./src/path_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
The value of the path parameter `item_id` will be passed to your function as the argument `item_id`.
|
||||
@@ -17,7 +17,7 @@ So, if you run this example and go to <a href="http://127.0.0.1:8000/items/foo"
|
||||
You can declare the type of a path parameter in the function, using standard Python type annotations:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/path_params/tutorial002.py!}
|
||||
{!./src/path_params/tutorial002.py!}
|
||||
```
|
||||
|
||||
In this case, `item_id` is declared to be an `int`.
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
**Python 3.6+** has support for optional "type hints".
|
||||
|
||||
These **"type hints"** are a new syntax (since Python 3.6+) that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
|
||||
|
||||
By declaring types for your variables, editors and tools can give you better support.
|
||||
|
||||
This is just a **quick tutorial / refresher** about Python type hints. It covers only the minimum necessary to use them with **FastAPI**... which is actually very little.
|
||||
|
||||
**FastAPI** is all based on these type hints, they give it many advantages and benefits.
|
||||
|
||||
But even if you never use **FastAPI**, you would benefit from learning a bit about them.
|
||||
|
||||
!!! note
|
||||
If you are a Python expert, and you already know everything about type hints, skip to the next chapter.
|
||||
|
||||
## Motivation
|
||||
|
||||
Let's start with a simple example:
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/python_types/tutorial001.py!}
|
||||
```
|
||||
|
||||
Calling this program outputs:
|
||||
|
||||
```
|
||||
John Doe
|
||||
```
|
||||
|
||||
The function does the following:
|
||||
|
||||
* Takes a `fist_name` and `last_name`.
|
||||
* Converts the first letter of each one to upper case with `title()`.
|
||||
* <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> them with a space in the middle.
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!./tutorial/src/python_types/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Edit it
|
||||
|
||||
It's a very simple program.
|
||||
|
||||
But now imagine that you were writing it from scratch.
|
||||
|
||||
At some point you would have started the definition of the function, you had the parameters ready...
|
||||
|
||||
But then you have to call "that method that converts the first letter to upper case".
|
||||
|
||||
Was it `upper`? Was it `uppercase`? `first_uppercase`? `capitalize`?
|
||||
|
||||
Then, you try with the old programer's friend, editor autocompletion.
|
||||
|
||||
You type the first parameter of the function, `first_name`, then a dot (`.`) and then hit `Ctrl+Space` to trigger the completion.
|
||||
|
||||
But, sadly, you get nothing useful:
|
||||
|
||||
<img src="/img/tutorial/python-types/image01.png">
|
||||
|
||||
### Add types
|
||||
|
||||
Let's modify a single line from the previous version.
|
||||
|
||||
We will change exactly this fragment, the parameters of the function, from:
|
||||
|
||||
```Python
|
||||
first_name, last_name
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```Python
|
||||
first_name: str, last_name: str
|
||||
```
|
||||
|
||||
That's it.
|
||||
|
||||
Those are the "type hints":
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/python_types/tutorial002.py!}
|
||||
```
|
||||
|
||||
That is not the same as declaring default values like would be with:
|
||||
|
||||
```Python
|
||||
first_name="john", last_name="doe"
|
||||
```
|
||||
|
||||
It's a different thing.
|
||||
|
||||
We are using colons (`:`), not equals (`=`).
|
||||
|
||||
And adding type hints normally doesn't change what happens from what would happen without them.
|
||||
|
||||
But now, imagine you are again in the middle of creating that function, but with type hints.
|
||||
|
||||
At the same point, you try to trigger the autocomplete with `Ctrl+Space` and you see:
|
||||
|
||||
<img src="/img/tutorial/python-types/image02.png">
|
||||
|
||||
With that, you can scroll, seeing the options, until you find the one that "rings a bell":
|
||||
|
||||
<img src="/img/tutorial/python-types/image03.png">
|
||||
|
||||
## More motivation
|
||||
|
||||
Check this function, it already has type hints:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/python_types/tutorial003.py!}
|
||||
```
|
||||
|
||||
Because the editor knows the types of the variables, you don't only get completion, you also get error checks:
|
||||
|
||||
<img src="/img/tutorial/python-types/image04.png">
|
||||
|
||||
Now you know that you have to fix it, convert `age` to a string with `str(age)`:
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!./tutorial/src/python_types/tutorial004.py!}
|
||||
```
|
||||
|
||||
|
||||
## Declaring types
|
||||
|
||||
You just saw the main place to declare type hints. As function parameters.
|
||||
|
||||
This is also the main place you would use them with **FastAPI**.
|
||||
|
||||
### Simple types
|
||||
|
||||
You can declare all the standard Python types, not only `str`.
|
||||
|
||||
You can use, for example:
|
||||
|
||||
* `int`
|
||||
* `float`
|
||||
* `bool`
|
||||
* `bytes`
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/python_types/tutorial005.py!}
|
||||
```
|
||||
|
||||
### Types with subtypes
|
||||
|
||||
There are some data structures that can contain other values, like `dict`, `list`, `set` and `tuple`. And the internal values can have their own type too.
|
||||
|
||||
To declare those types and the subtypes, you can use the standard Python module `typing`.
|
||||
|
||||
It exists specifically to support these type hints.
|
||||
|
||||
#### Lists
|
||||
|
||||
For example, let's define a variable to be a `list` of `str`.
|
||||
|
||||
From `typing`, import `List` (with a capital `L`):
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/python_types/tutorial006.py!}
|
||||
```
|
||||
|
||||
Declare the variable, with the same colon (`:`) syntax.
|
||||
|
||||
As the type, put the `List`.
|
||||
|
||||
As the list is a type that takes a "subtype", you put the subtype in square brackets:
|
||||
|
||||
```Python hl_lines="4"
|
||||
{!./tutorial/src/python_types/tutorial006.py!}
|
||||
```
|
||||
|
||||
That means: "the variable `items` is a `list`, and each of the items in this list is a `str`".
|
||||
|
||||
By doing that, your editor can provide support even while processing items from the list.
|
||||
|
||||
Without types, that's almost impossible to achieve:
|
||||
|
||||
<img src="/img/tutorial/python-types/image05.png">
|
||||
|
||||
Notice that the variable `item` is one of the elements in the list `items`.
|
||||
|
||||
And still, the editor knows it is a `str`, and provides support for that.
|
||||
|
||||
#### Tuples and Sets
|
||||
|
||||
You would do the same to declare `tuple`s and `set`s:
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!./tutorial/src/python_types/tutorial007.py!}
|
||||
```
|
||||
|
||||
This means:
|
||||
|
||||
* The variable `items_t` is a `tuple`, and each of its items is an `int`.
|
||||
* The variable `items_s` is a `set`, and each of its items is of type `bytes`.
|
||||
|
||||
#### Dicts
|
||||
|
||||
To define a `dict`, you pass 2 subtypes, separated by commas.
|
||||
|
||||
The first subtype is for the keys of the `dict`.
|
||||
|
||||
The second subtype is for the values of the `dict`:
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!./tutorial/src/python_types/tutorial008.py!}
|
||||
```
|
||||
|
||||
This means:
|
||||
|
||||
* The variable `prices` is a `dict`:
|
||||
* The keys of this `dict` are of type `str` (let's say, the name of each item).
|
||||
* The values of this `dict` are of type `float` (let's say, the price of each item).
|
||||
|
||||
|
||||
### Classes as types
|
||||
|
||||
You can also declare a class as the type of a variable.
|
||||
|
||||
Let's say you have a class `Person`, with a name:
|
||||
|
||||
```Python hl_lines="1 2 3"
|
||||
{!./tutorial/src/python_types/tutorial009.py!}
|
||||
```
|
||||
|
||||
Then you can declare a variable to be of type `Person`:
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!./tutorial/src/python_types/tutorial009.py!}
|
||||
```
|
||||
|
||||
And then, again, you get all the editor support:
|
||||
|
||||
<img src="/img/tutorial/python-types/image06.png">
|
||||
|
||||
|
||||
## Pydantic models
|
||||
|
||||
<a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a> is a Python library to perform data validation.
|
||||
|
||||
You declare the "shape" of the data as classes with attributes.
|
||||
|
||||
And each attribute has a type.
|
||||
|
||||
Then you create an instance of that class with some values and it will validate the values, convert them to the appropriate type (if that's the case) and give you an object with all the data.
|
||||
|
||||
And you get all the editor support with that resulting object.
|
||||
|
||||
Taken from the official Pydantic docs:
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/python_types/tutorial010.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
To learn more about <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic, check its docs</a>.
|
||||
|
||||
**FastAPI** is all based on Pydantic.
|
||||
|
||||
You will see a lot more of all this in practice in the next chapters.
|
||||
|
||||
|
||||
## Type hints in **FastAPI**
|
||||
|
||||
**FastAPI** takes advantage of these type hints to do several things.
|
||||
|
||||
With **FastAPI** you declare parameters with type hints and you get:
|
||||
|
||||
* **Editor support**.
|
||||
* **Type checks**.
|
||||
|
||||
...and **FastAPI** uses the same declarations to:
|
||||
|
||||
* **Define requirements**: from request path parameters, query parameters, headers, bodies, dependencies, etc.
|
||||
* **Convert data**: from the request to the required type.
|
||||
* **Validate data**: coming from each request:
|
||||
* Generating **automatic errors** returned to the client when the data is invalid.
|
||||
* **Document** the API using OpenAPI:
|
||||
* which is then used by the automatic interactive documentation user interfaces.
|
||||
|
||||
This might all sound abstract. Don't worry. You'll see all this in action in the next chapters.
|
||||
|
||||
The important thing is that by using standard Python types, in a single place (instead of adding more classes, decorators, etc), **FastAPI** will do a lot of the work for you.
|
||||
|
||||
!!! info
|
||||
If you already went through all the tutorial and came back to see more about types, a good resource is <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" target="_blank">the "cheat sheet" from `mypy`</a>.
|
||||
@@ -3,7 +3,7 @@
|
||||
Let's take this application as example:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial001.py!}
|
||||
{!./src/query_params_str_validations/tutorial001.py!}
|
||||
```
|
||||
|
||||
The query parameter `q` is of type `str`, and by default is `None`, so it is optional.
|
||||
@@ -18,7 +18,7 @@ We are going to enforce that even though `q` is optional, whenever it is provide
|
||||
To achieve that, first import `Query` from `fastapi`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial002.py!}
|
||||
{!./src/query_params_str_validations/tutorial002.py!}
|
||||
```
|
||||
|
||||
## Use `Query` as the default value
|
||||
@@ -26,7 +26,7 @@ To achieve that, first import `Query` from `fastapi`:
|
||||
And now use it as the default value of your parameter, setting the parameter `max_length` to 50:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial002.py!}
|
||||
{!./src/query_params_str_validations/tutorial002.py!}
|
||||
```
|
||||
|
||||
As we have to replace the default value `None` with `Query(None)`, the first parameter to `Query` serves the same purpose of defining that default value.
|
||||
@@ -59,7 +59,7 @@ This will validate the data, show a clear error when the data is not valid, and
|
||||
You can also add a parameter `min_length`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial003.py!}
|
||||
{!./src/query_params_str_validations/tutorial003.py!}
|
||||
```
|
||||
|
||||
## Add regular expressions
|
||||
@@ -67,7 +67,7 @@ You can also add a parameter `min_length`:
|
||||
You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> that the parameter should match:
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial004.py!}
|
||||
{!./src/query_params_str_validations/tutorial004.py!}
|
||||
```
|
||||
|
||||
This specific regular expression checks that the received parameter value:
|
||||
@@ -87,7 +87,7 @@ The same way that you can pass `None` as the first argument to be used as the de
|
||||
Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial005.py!}
|
||||
{!./src/query_params_str_validations/tutorial005.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -116,7 +116,7 @@ q: str = Query(None, min_length=3)
|
||||
So, when you need to declare a value as required while using `Query`, you can use `...` as the first argument:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial006.py!}
|
||||
{!./src/query_params_str_validations/tutorial006.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
@@ -133,13 +133,13 @@ That information will be included in the generated OpenAPI and used by the docum
|
||||
You can add a `title`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial007.py!}
|
||||
{!./src/query_params_str_validations/tutorial007.py!}
|
||||
```
|
||||
|
||||
And a `description`:
|
||||
|
||||
```Python hl_lines="11"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial008.py!}
|
||||
{!./src/query_params_str_validations/tutorial008.py!}
|
||||
```
|
||||
|
||||
## Alias parameters
|
||||
@@ -161,7 +161,7 @@ But you still need it to be exactly `item-query`...
|
||||
Then you can declare an `alias`, and that alias is what will be used to find the parameter value:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial009.py!}
|
||||
{!./src/query_params_str_validations/tutorial009.py!}
|
||||
```
|
||||
|
||||
## Deprecating parameters
|
||||
@@ -173,7 +173,7 @@ You have to leave it there a while because there are clients using it, but you w
|
||||
Then pass the parameter `deprecated=True` to `Query`:
|
||||
|
||||
```Python hl_lines="16"
|
||||
{!./tutorial/src/query_params_str_validations/tutorial010.py!}
|
||||
{!./src/query_params_str_validations/tutorial010.py!}
|
||||
```
|
||||
|
||||
The docs will show it like this:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters.
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!./tutorial/src/query_params/tutorial001.py!}
|
||||
{!./src/query_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
The query is the set of key-value pairs that go after the `?` in a URL, separated by `&` characters.
|
||||
@@ -62,7 +62,7 @@ The parameter values in your function will be:
|
||||
The same way, you can declare optional query parameters, by setting their default to `None`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params/tutorial002.py!}
|
||||
{!./src/query_params/tutorial002.py!}
|
||||
```
|
||||
|
||||
In this case, the function parameter `q` will be optional, and will be `None` by default.
|
||||
@@ -75,7 +75,7 @@ In this case, the function parameter `q` will be optional, and will be `None` by
|
||||
You can also declare `bool` types, and they will be converted:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params/tutorial003.py!}
|
||||
{!./src/query_params/tutorial003.py!}
|
||||
```
|
||||
|
||||
In this case, if you go to:
|
||||
@@ -120,7 +120,7 @@ And you don't have to declare them in any specific order.
|
||||
They will be detected by name:
|
||||
|
||||
```Python hl_lines="6 8"
|
||||
{!./tutorial/src/query_params/tutorial004.py!}
|
||||
{!./src/query_params/tutorial004.py!}
|
||||
```
|
||||
|
||||
## Required query parameters
|
||||
@@ -132,7 +132,7 @@ If you don't want to add a specific value but just make it optional, set the def
|
||||
But when you want to make a query parameter required, you can just do not declare any default value:
|
||||
|
||||
```Python hl_lines="6 7"
|
||||
{!./tutorial/src/query_params/tutorial005.py!}
|
||||
{!./src/query_params/tutorial005.py!}
|
||||
```
|
||||
|
||||
Here the query parameter `needy` is a required query parameter of type `str`.
|
||||
@@ -178,7 +178,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
And of course, you can define some parameters as required, some as having a default value, and some entirely optional:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query_params/tutorial006.py!}
|
||||
{!./src/query_params/tutorial006.py!}
|
||||
```
|
||||
|
||||
In this case, there are 3 query parameters:
|
||||
|
||||
@@ -5,7 +5,7 @@ You can define files to be uploaded by the client using `File`.
|
||||
Import `File` from `fastapi`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/request_files/tutorial001.py!}
|
||||
{!./src/request_files/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Define `File` parameters
|
||||
@@ -13,7 +13,7 @@ Import `File` from `fastapi`:
|
||||
Create file parameters the same way you would for `Body` or `Form`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/request_files/tutorial001.py!}
|
||||
{!./src/request_files/tutorial001.py!}
|
||||
```
|
||||
|
||||
The files will be uploaded as form data and you will receive the contents as `bytes`.
|
||||
|
||||
@@ -3,7 +3,7 @@ You can define files and form fields at the same time using `File` and `Form`.
|
||||
## Import `File` and `Form`
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/request_forms_and_files/tutorial001.py!}
|
||||
{!./src/request_forms_and_files/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Define `File` and `Form` parameters
|
||||
@@ -11,7 +11,7 @@ You can define files and form fields at the same time using `File` and `Form`.
|
||||
Create file and form parameters the same way you would for `Body` or `Query`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/request_forms_and_files/tutorial001.py!}
|
||||
{!./src/request_forms_and_files/tutorial001.py!}
|
||||
```
|
||||
|
||||
The files and form fields will be uploaded as form data and you will receive the files and form fields.
|
||||
|
||||
@@ -5,7 +5,7 @@ When you need to receive form fields instead of JSON, you can use `Form`.
|
||||
Import `Form` from `fastapi`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./tutorial/src/request_forms/tutorial001.py!}
|
||||
{!./src/request_forms/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Define `Form` parameters
|
||||
@@ -13,7 +13,7 @@ Import `Form` from `fastapi`:
|
||||
Create form parameters the same way you would for `Body` or `Query`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/request_forms/tutorial001.py!}
|
||||
{!./src/request_forms/tutorial001.py!}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
@@ -7,7 +7,7 @@ You can declare the model used for the response with the parameter `response_mod
|
||||
* etc.
|
||||
|
||||
```Python hl_lines="17"
|
||||
{!./tutorial/src/response_model/tutorial001.py!}
|
||||
{!./src/response_model/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -29,13 +29,13 @@ But most importantly:
|
||||
Here we are declaring a `UserIn` model, it will contain a plaintext password:
|
||||
|
||||
```Python hl_lines="8 10"
|
||||
{!./tutorial/src/response_model/tutorial002.py!}
|
||||
{!./src/response_model/tutorial002.py!}
|
||||
```
|
||||
|
||||
And we are using this model to declare our input and the same model to declare our output:
|
||||
|
||||
```Python hl_lines="16 17"
|
||||
{!./tutorial/src/response_model/tutorial002.py!}
|
||||
{!./src/response_model/tutorial002.py!}
|
||||
```
|
||||
|
||||
Now, whenever a browser is creating a user with a password, the API will return the same password in the response.
|
||||
@@ -52,19 +52,19 @@ But if we use sthe same model for another path operation, we could be sending th
|
||||
We can instead create an input model with the plaintext password and an output model without it:
|
||||
|
||||
```Python hl_lines="8 10 15"
|
||||
{!./tutorial/src/response_model/tutorial003.py!}
|
||||
{!./src/response_model/tutorial003.py!}
|
||||
```
|
||||
|
||||
Here, even though our path operation function is returning the same input user that contains the password:
|
||||
|
||||
```Python hl_lines="23"
|
||||
{!./tutorial/src/response_model/tutorial003.py!}
|
||||
{!./src/response_model/tutorial003.py!}
|
||||
```
|
||||
|
||||
...we declared the `response_model` to be our model `UserOut`, that doesn't include the password:
|
||||
|
||||
```Python hl_lines="21"
|
||||
{!./tutorial/src/response_model/tutorial003.py!}
|
||||
{!./src/response_model/tutorial003.py!}
|
||||
```
|
||||
|
||||
So, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Coming soon...
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/security/tutorial002.py!}
|
||||
{!./src/security/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Coming soon...
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/security/tutorial001.py!}
|
||||
{!./src/security/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Coming soon...
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/security/tutorial004.py!}
|
||||
{!./src/security/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Coming soon...
|
||||
|
||||
```Python
|
||||
{!./tutorial/src/security/tutorial003.py!}
|
||||
{!./src/security/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -24,7 +24,7 @@ In this example, we'll use **PostgreSQL**.
|
||||
For now, don't pay attention to the rest, only the imports:
|
||||
|
||||
```Python hl_lines="3 4 5"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Define the database
|
||||
@@ -32,7 +32,7 @@ For now, don't pay attention to the rest, only the imports:
|
||||
Define the database that SQLAlchemy should connect to:
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
@@ -41,13 +41,13 @@ Define the database that SQLAlchemy should connect to:
|
||||
## Create the SQLAlchemy `engine`
|
||||
|
||||
```Python hl_lines="10"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Create a `scoped_session`
|
||||
|
||||
```Python hl_lines="11 12 13"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note "Very Technical Details"
|
||||
@@ -70,13 +70,13 @@ That way you don't have to declare them explicitly.
|
||||
So, your models will behave very similarly to, for example, Flask-SQLAlchemy.
|
||||
|
||||
```Python hl_lines="15 16 17 18 19"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Create the SQLAlchemy `Base` model
|
||||
|
||||
```Python hl_lines="22"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Create your application data model
|
||||
@@ -86,7 +86,7 @@ Now this is finally code specific to your app.
|
||||
Here's a user model that will be a table in the database:
|
||||
|
||||
```Python hl_lines="25 26 27 28 29"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Get a user
|
||||
@@ -94,7 +94,7 @@ Here's a user model that will be a table in the database:
|
||||
By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your path operation function, you can more easily re-use it in multiple parts and also add <abbr title="Automated test, written in code, that checks if another piece of code is working correctly.">unit tests</abbr> for it:
|
||||
|
||||
```Python hl_lines="32 33"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Create your **FastAPI** code
|
||||
@@ -104,7 +104,7 @@ Now, finally, here's the standard **FastAPI** code.
|
||||
Create your app and path operation function:
|
||||
|
||||
```Python hl_lines="37 40 41 42 43"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
As we are using SQLAlchemy's `scoped_session`, we don't even have to create a dependency with `Depends`.
|
||||
@@ -132,7 +132,7 @@ user = get_user(username, db_session)
|
||||
Then we should declare the path operation without `async def`, just with a normal `def`:
|
||||
|
||||
```Python hl_lines="41"
|
||||
{!./tutorial/src/sql_databases/tutorial001.py!}
|
||||
{!./src/sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Migrations
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI(
|
||||
title="My Super Project",
|
||||
description="This is a very fancy project, with auto docs for the API and everything",
|
||||
version="2.5.0",
|
||||
)
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items():
|
||||
return [{"name": "Foo"}]
|
||||
@@ -1,10 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI(
|
||||
title="My Super Project", version="2.5.0", openapi_url="/api/v1/openapi.json"
|
||||
)
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items():
|
||||
return [{"name": "Foo"}]
|
||||
@@ -1,14 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI(
|
||||
title="My Super Project",
|
||||
version="2.5.0",
|
||||
openapi_url="/api/v1/openapi.json",
|
||||
docs_url="/api/v1/docs",
|
||||
redoc_url=None,
|
||||
)
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items():
|
||||
return [{"name": "Foo"}]
|
||||
@@ -1,18 +0,0 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/users/")
|
||||
async def read_users():
|
||||
return [{"username": "Foo"}, {"username": "Bar"}]
|
||||
|
||||
|
||||
@router.get("/users/me")
|
||||
async def read_user_me():
|
||||
return {"username": "fakecurrentuser"}
|
||||
|
||||
|
||||
@router.get("/users/{username}")
|
||||
async def read_user(username: str):
|
||||
return {"username": username}
|
||||
@@ -1,13 +0,0 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def read_items():
|
||||
return [{"name": "Item Foo"}, {"name": "item Bar"}]
|
||||
|
||||
|
||||
@router.get("/{item_id}")
|
||||
async def read_item(item_id: str):
|
||||
return {"name": "Fake Specific Item", "item_id": item_id}
|
||||
@@ -1,9 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
from .routers.tutorial001 import router as users_router
|
||||
from .routers.tutorial002 import router as items_router
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
app.include_router(users_router)
|
||||
app.include_router(items_router, prefix="/items")
|
||||
@@ -1,17 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.post("/items/")
|
||||
async def create_item(item: Item):
|
||||
return item
|
||||
@@ -1,21 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.post("/items/")
|
||||
async def create_item(item: Item):
|
||||
item_dict = item.dict()
|
||||
if item.tax:
|
||||
price_with_tax = item.price + item.tax
|
||||
item_dict.update({"price_with_tax": price_with_tax})
|
||||
return item_dict
|
||||
@@ -1,17 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def create_item(item_id: int, item: Item):
|
||||
return {"item_id": item_id, **item.dict()}
|
||||
@@ -1,20 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def create_item(item_id: int, item: Item, q: str = None):
|
||||
result = {"item_id": item_id, **item.dict()}
|
||||
if q:
|
||||
result.update({"q": q})
|
||||
return result
|
||||
@@ -1,26 +0,0 @@
|
||||
from fastapi import FastAPI, Path
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(
|
||||
*,
|
||||
item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
|
||||
q: str = None,
|
||||
item: Item = None,
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
if item:
|
||||
results.update({"item": item})
|
||||
return results
|
||||
@@ -1,22 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
full_name: str = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(*, item_id: int, item: Item, user: User):
|
||||
results = {"item_id": item_id, "item": item, "user": user}
|
||||
return results
|
||||
@@ -1,24 +0,0 @@
|
||||
from fastapi import Body, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
full_name: str = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(
|
||||
*, item_id: int, item: Item, user: User, importance: int = Body(...)
|
||||
):
|
||||
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
|
||||
return results
|
||||
@@ -1,31 +0,0 @@
|
||||
from fastapi import Body, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
full_name: str = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(
|
||||
*,
|
||||
item_id: int,
|
||||
item: Item,
|
||||
user: User,
|
||||
importance: int = Body(..., gt=0),
|
||||
q: str = None
|
||||
):
|
||||
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
return results
|
||||
@@ -1,17 +0,0 @@
|
||||
from fastapi import Body, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(*, item_id: int, item: Item = Body(..., embed=True)):
|
||||
results = {"item_id": item_id, "item": item}
|
||||
return results
|
||||
@@ -1,18 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: list = []
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(*, item_id: int, item: Item):
|
||||
results = {"item_id": item_id, "item": item}
|
||||
return results
|
||||
@@ -1,20 +0,0 @@
|
||||
from typing import List
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: List[str] = []
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(*, item_id: int, item: Item):
|
||||
results = {"item_id": item_id, "item": item}
|
||||
return results
|
||||
@@ -1,20 +0,0 @@
|
||||
from typing import Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = set()
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(*, item_id: int, item: Item):
|
||||
results = {"item_id": item_id, "item": item}
|
||||
return results
|
||||
@@ -1,26 +0,0 @@
|
||||
from typing import Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Image(BaseModel):
|
||||
url: str
|
||||
name: str
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
image: Image = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(*, item_id: int, item: Item):
|
||||
results = {"item_id": item_id, "item": item}
|
||||
return results
|
||||
@@ -1,27 +0,0 @@
|
||||
from typing import Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import UrlStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Image(BaseModel):
|
||||
url: UrlStr
|
||||
name: str
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
image: Image = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(*, item_id: int, item: Item):
|
||||
results = {"item_id": item_id, "item": item}
|
||||
return results
|
||||
@@ -1,27 +0,0 @@
|
||||
from typing import List, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import UrlStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Image(BaseModel):
|
||||
url: UrlStr
|
||||
name: str
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
image: List[Image] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(*, item_id: int, item: Item):
|
||||
results = {"item_id": item_id, "item": item}
|
||||
return results
|
||||
@@ -1,33 +0,0 @@
|
||||
from typing import List, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import UrlStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Image(BaseModel):
|
||||
url: UrlStr
|
||||
name: str
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
image: List[Image] = None
|
||||
|
||||
|
||||
class Offer(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
items: List[Item]
|
||||
|
||||
|
||||
@app.post("/offers/")
|
||||
async def create_offer(*, offer: Offer):
|
||||
return offer
|
||||
@@ -1,17 +0,0 @@
|
||||
from typing import List
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import UrlStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Image(BaseModel):
|
||||
url: UrlStr
|
||||
name: str
|
||||
|
||||
|
||||
@app.post("/images/multiple/")
|
||||
async def create_multiple_images(*, images: List[Image]):
|
||||
return images
|
||||
@@ -1,17 +0,0 @@
|
||||
from fastapi import Body, FastAPI
|
||||
from pydantic import BaseModel, Schema
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = Schema(None, title="The description of the item", max_length=300)
|
||||
price: float = Schema(..., gt=0, description="The price must be greater than zero")
|
||||
tax: float = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(*, item_id: int, item: Item = Body(..., embed=True)):
|
||||
results = {"item_id": item_id, "item": item}
|
||||
return results
|
||||
@@ -1,29 +0,0 @@
|
||||
from fastapi import Body, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(
|
||||
*,
|
||||
item_id: int,
|
||||
item: Item = Body(
|
||||
...,
|
||||
example={
|
||||
"name": "Foo",
|
||||
"description": "A very nice Item",
|
||||
"price": 35.4,
|
||||
"tax": 3.2,
|
||||
},
|
||||
)
|
||||
):
|
||||
results = {"item_id": item_id, "item": item}
|
||||
return results
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import Cookie, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(*, ads_id: str = Cookie(None)):
|
||||
return {"ads_id": ads_id}
|
||||
@@ -1,9 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from starlette.responses import UJSONResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/", content_type=UJSONResponse)
|
||||
async def read_items():
|
||||
return [{"item_id": "Foo"}]
|
||||
@@ -1,18 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from starlette.responses import HTMLResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/", content_type=HTMLResponse)
|
||||
async def read_items():
|
||||
return """
|
||||
<html>
|
||||
<head>
|
||||
<title>Some HTML in here</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Look ma! HTML!</h1>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
@@ -1,19 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from starlette.responses import HTMLResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items():
|
||||
html_content = """
|
||||
<html>
|
||||
<head>
|
||||
<title>Some HTML in here</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Look ma! HTML!</h1>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return HTMLResponse(content=html_content, status_code=200)
|
||||
@@ -1,23 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from starlette.responses import HTMLResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def generate_html_response():
|
||||
html_content = """
|
||||
<html>
|
||||
<head>
|
||||
<title>Some HTML in here</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Look ma! HTML!</h1>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return HTMLResponse(content=html_content, status_code=200)
|
||||
|
||||
|
||||
@app.get("/items/", content_type=HTMLResponse)
|
||||
async def read_items():
|
||||
return generate_html_response()
|
||||
@@ -1,12 +0,0 @@
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
|
||||
return {"q": q, "skip": skip, "limit": limit}
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(commons: dict = Depends(common_parameters)):
|
||||
return commons
|
||||
@@ -1,27 +0,0 @@
|
||||
from fastapi import Depends, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
|
||||
|
||||
|
||||
class CommonQueryParams(BaseModel):
|
||||
q: str = None
|
||||
skip: int = None
|
||||
limit: int = None
|
||||
|
||||
|
||||
async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
|
||||
return CommonQueryParams(q=q, skip=skip, limit=limit)
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(commons: CommonQueryParams = Depends(common_parameters)):
|
||||
response = {}
|
||||
if commons.q:
|
||||
response.update({"q": commons.q})
|
||||
items = fake_items_db[commons.skip : commons.limit]
|
||||
response.update({"items": items})
|
||||
return response
|
||||
@@ -1,34 +0,0 @@
|
||||
from typing import List
|
||||
|
||||
from fastapi import Cookie, Depends, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class InterestsTracker(BaseModel):
|
||||
track_code: str
|
||||
interests: List[str]
|
||||
|
||||
|
||||
fake_tracked_users_db = {
|
||||
"Foo": {"track_code": "Foo", "interests": ["sports", "movies"]},
|
||||
"Bar": {"track_code": "Bar", "interests": ["food", "shows"]},
|
||||
"Baz": {"track_code": "Baz", "interests": ["gaming", "virtual reality"]},
|
||||
}
|
||||
|
||||
|
||||
async def get_tracked_interests(track_code: str = Cookie(None)):
|
||||
if track_code in fake_tracked_users_db:
|
||||
track_dict = fake_tracked_users_db[track_code]
|
||||
track = InterestsTracker(**track_dict)
|
||||
return track
|
||||
return None
|
||||
|
||||
|
||||
@app.get("/interests/")
|
||||
async def read_interests(
|
||||
tracked_interests: InterestsTracker = Depends(get_tracked_interests)
|
||||
):
|
||||
response = {"interests": tracked_interests.interests}
|
||||
return response
|
||||
@@ -1,49 +0,0 @@
|
||||
from random import choice
|
||||
from typing import List
|
||||
|
||||
from fastapi import Cookie, Depends, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class InterestsTracker(BaseModel):
|
||||
track_code: str
|
||||
interests: List[str]
|
||||
|
||||
|
||||
fake_tracked_users_db = {
|
||||
"Foo": {"track_code": "Foo", "interests": ["sports", "movies"]},
|
||||
"Bar": {"track_code": "Bar", "interests": ["food", "shows"]},
|
||||
"Baz": {"track_code": "Baz", "interests": ["gaming", "virtual reality"]},
|
||||
}
|
||||
|
||||
|
||||
async def get_tracked_interests(track_code: str = Cookie(None)):
|
||||
if track_code in fake_tracked_users_db:
|
||||
track_dict = fake_tracked_users_db[track_code]
|
||||
track = InterestsTracker(**track_dict)
|
||||
return track
|
||||
return None
|
||||
|
||||
|
||||
class ComplexTracker:
|
||||
def __init__(self, tracker: InterestsTracker = Depends(get_tracked_interests)):
|
||||
self.tracker = tracker
|
||||
|
||||
def random_interest(self):
|
||||
"""
|
||||
Get a random interest from the tracked ones for the current user.
|
||||
If the user doesn't have tracked interests, return a random one from the ones available.
|
||||
"""
|
||||
if self.tracker.interests:
|
||||
return choice(self.tracker.interests)
|
||||
return choice(
|
||||
["sports", "movies", "food", "shows", "gaming", "virtual reality"]
|
||||
)
|
||||
|
||||
|
||||
@app.get("/suggested-category")
|
||||
async def read_suggested_category(tracker: ComplexTracker = Depends(None)):
|
||||
response = {"category": tracker.random_interest()}
|
||||
return response
|
||||
@@ -1,42 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import EmailStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class UserIn(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
email: EmailStr
|
||||
full_name: str = None
|
||||
|
||||
|
||||
class UserOut(BaseModel):
|
||||
username: str
|
||||
email: EmailStr
|
||||
full_name: str = None
|
||||
|
||||
|
||||
class UserInDB(BaseModel):
|
||||
username: str
|
||||
hashed_password: str
|
||||
email: EmailStr
|
||||
full_name: str = None
|
||||
|
||||
|
||||
def fake_password_hasher(raw_password: str):
|
||||
return "supersecret" + raw_password
|
||||
|
||||
|
||||
def fake_save_user(user_in: UserIn):
|
||||
hashed_password = fake_password_hasher(user_in.password)
|
||||
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
print("User saved! ..not really")
|
||||
return user_in_db
|
||||
|
||||
|
||||
@app.post("/user/", response_model=UserOut)
|
||||
async def create_user(*, user_in: UserIn):
|
||||
user_saved = fake_save_user(user_in)
|
||||
return user_saved
|
||||
@@ -1,40 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import EmailStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class UserBase(BaseModel):
|
||||
username: str
|
||||
email: EmailStr
|
||||
full_name: str = None
|
||||
|
||||
|
||||
class UserIn(UserBase):
|
||||
password: str
|
||||
|
||||
|
||||
class UserOut(UserBase):
|
||||
pass
|
||||
|
||||
|
||||
class UserInDB(UserBase):
|
||||
hashed_password: str
|
||||
|
||||
|
||||
def fake_password_hasher(raw_password: str):
|
||||
return "supersecret" + raw_password
|
||||
|
||||
|
||||
def fake_save_user(user_in: UserIn):
|
||||
hashed_password = fake_password_hasher(user_in.password)
|
||||
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
print("User saved! ..not really")
|
||||
return user_in_db
|
||||
|
||||
|
||||
@app.post("/user/", response_model=UserOut)
|
||||
async def create_user(*, user_in: UserIn):
|
||||
user_saved = fake_save_user(user_in)
|
||||
return user_saved
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return {"message": "Hello World"}
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
my_awesome_api = FastAPI()
|
||||
|
||||
|
||||
@my_awesome_api.get("/")
|
||||
async def root():
|
||||
return {"message": "Hello World"}
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def root():
|
||||
return {"message": "Hello World"}
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import FastAPI, Header
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(*, user_agent: str = Header(None)):
|
||||
return {"User-Agent": user_agent}
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import FastAPI, Header
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(*, strange_header: str = Header(None, convert_underscores=False)):
|
||||
return {"strange_header": strange_header}
|
||||
@@ -1,54 +0,0 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
from couchbase import LOCKMODE_WAIT
|
||||
from couchbase.bucket import Bucket
|
||||
from couchbase.cluster import Cluster, PasswordAuthenticator
|
||||
|
||||
USERPROFILE_DOC_TYPE = "userprofile"
|
||||
|
||||
|
||||
def get_bucket():
|
||||
cluster = Cluster(
|
||||
"couchbase://couchbasehost:8091?fetch_mutation_tokens=1&operation_timeout=30&n1ql_timeout=300"
|
||||
)
|
||||
authenticator = PasswordAuthenticator("username", "password")
|
||||
cluster.authenticate(authenticator)
|
||||
bucket: Bucket = cluster.open_bucket("bucket_name", lockmode=LOCKMODE_WAIT)
|
||||
bucket.timeout = 30
|
||||
bucket.n1ql_timeout = 300
|
||||
return bucket
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
email: Optional[str] = None
|
||||
full_name: Optional[str] = None
|
||||
disabled: Optional[bool] = None
|
||||
|
||||
|
||||
class UserInDB(User):
|
||||
type: str = USERPROFILE_DOC_TYPE
|
||||
hashed_password: str
|
||||
|
||||
|
||||
def get_user(bucket: Bucket, username: str):
|
||||
doc_id = f"userprofile::{username}"
|
||||
result = bucket.get(doc_id, quiet=True)
|
||||
if not result.value:
|
||||
return None
|
||||
user = UserInDB(**result.value)
|
||||
return user
|
||||
|
||||
|
||||
# FastAPI specific code
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/users/{username}", response_model=User)
|
||||
def read_user(username: str):
|
||||
bucket = get_bucket()
|
||||
user = get_user(bucket=bucket, username=username)
|
||||
return user
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/", operation_id="some_specific_id_you_define")
|
||||
async def read_items():
|
||||
return [{"item_id": "Foo"}]
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/", include_in_schema=False)
|
||||
async def read_items():
|
||||
return [{"item_id": "Foo"}]
|
||||
@@ -1,20 +0,0 @@
|
||||
from typing import Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from starlette.status import HTTP_201_CREATED
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
@app.post("/items/", response_model=Item, status_code=HTTP_201_CREATED)
|
||||
async def create_item(*, item: Item):
|
||||
return item
|
||||
@@ -1,29 +0,0 @@
|
||||
from typing import Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
@app.post("/items/", response_model=Item, tags=["items"])
|
||||
async def create_item(*, item: Item):
|
||||
return item
|
||||
|
||||
|
||||
@app.get("/items/", tags=["items"])
|
||||
async def read_items():
|
||||
return [{"name": "Foo", "price": 42}]
|
||||
|
||||
|
||||
@app.get("/users/", tags=["users"])
|
||||
async def read_users():
|
||||
return [{"username": "johndoe"}]
|
||||
@@ -1,24 +0,0 @@
|
||||
from typing import Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
@app.post(
|
||||
"/items/",
|
||||
response_model=Item,
|
||||
summary="Create an item",
|
||||
description="Create an item with all the information, name, description, price, tax and a set of unique tags",
|
||||
)
|
||||
async def create_item(*, item: Item):
|
||||
return item
|
||||
@@ -1,28 +0,0 @@
|
||||
from typing import Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
@app.post("/items/", response_model=Item, summary="Create an item")
|
||||
async def create_item(*, item: Item):
|
||||
"""
|
||||
Create an item with all the information:
|
||||
|
||||
* name: each item must have a name
|
||||
* description: a long description
|
||||
* price: required
|
||||
* tax: if the item doesn't have tax, you can omit this
|
||||
* tags: a set of unique tag strings for this item
|
||||
"""
|
||||
return item
|
||||
@@ -1,33 +0,0 @@
|
||||
from typing import Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
@app.post(
|
||||
"/items/",
|
||||
response_model=Item,
|
||||
summary="Create an item",
|
||||
response_description="The created item",
|
||||
)
|
||||
async def create_item(*, item: Item):
|
||||
"""
|
||||
Create an item with all the information:
|
||||
|
||||
* name: each item must have a name
|
||||
* description: a long description
|
||||
* price: required
|
||||
* tax: if the item doesn't have tax, you can omit this
|
||||
* tags: a set of unique tag strings for this item
|
||||
"""
|
||||
return item
|
||||
@@ -1,18 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/", tags=["items"])
|
||||
async def read_items():
|
||||
return [{"name": "Foo", "price": 42}]
|
||||
|
||||
|
||||
@app.get("/users/", tags=["users"])
|
||||
async def read_users():
|
||||
return [{"username": "johndoe"}]
|
||||
|
||||
|
||||
@app.get("/elements/", tags=["items"], deprecated=True)
|
||||
async def read_elements():
|
||||
return [{"item_id": "Foo"}]
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id):
|
||||
return {"item_id": item_id}
|
||||
@@ -1,8 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int):
|
||||
return {"item_id": item_id}
|
||||
@@ -1,10 +0,0 @@
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: UUID):
|
||||
return {"item_id": item_id}
|
||||
@@ -1,14 +0,0 @@
|
||||
from fastapi import FastAPI, Path, Query
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_items(
|
||||
item_id: int = Path(..., title="The ID of the item to get"),
|
||||
q: str = Query(None, alias="item-query"),
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
return results
|
||||
@@ -1,13 +0,0 @@
|
||||
from fastapi import FastAPI, Path
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_items(
|
||||
q: str, item_id: int = Path(..., title="The ID of the item to get")
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
return results
|
||||
@@ -1,13 +0,0 @@
|
||||
from fastapi import FastAPI, Path
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_items(
|
||||
*, item_id: int = Path(..., title="The ID of the item to get"), q: str
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
return results
|
||||
@@ -1,13 +0,0 @@
|
||||
from fastapi import FastAPI, Path
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_items(
|
||||
*, item_id: int = Path(..., title="The ID of the item to get", ge=1), q: str
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
return results
|
||||
@@ -1,15 +0,0 @@
|
||||
from fastapi import FastAPI, Path
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_items(
|
||||
*,
|
||||
item_id: int = Path(..., title="The ID of the item to get", gt=0, le=1000),
|
||||
q: str,
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
return results
|
||||
@@ -1,16 +0,0 @@
|
||||
from fastapi import FastAPI, Path, Query
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_items(
|
||||
*,
|
||||
item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
|
||||
q: str,
|
||||
size: float = Query(..., gt=0, lt=10.5)
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
return results
|
||||
@@ -1,6 +0,0 @@
|
||||
def get_full_name(first_name, last_name):
|
||||
full_name = first_name.title() + " " + last_name.title()
|
||||
return full_name
|
||||
|
||||
|
||||
print(get_full_name("john", "doe"))
|
||||
@@ -1,6 +0,0 @@
|
||||
def get_full_name(first_name: str, last_name: str):
|
||||
full_name = first_name.title() + " " + last_name.title()
|
||||
return full_name
|
||||
|
||||
|
||||
print(get_full_name("john", "doe"))
|
||||
@@ -1,3 +0,0 @@
|
||||
def get_name_with_age(name: str, age: int):
|
||||
name_with_age = name + " is this old: " + age
|
||||
return name_with_age
|
||||
@@ -1,3 +0,0 @@
|
||||
def get_name_with_age(name: str, age: int):
|
||||
name_with_age = name + " is this old: " + str(age)
|
||||
return name_with_age
|
||||
@@ -1,2 +0,0 @@
|
||||
def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
|
||||
return item_a, item_b, item_c, item_d, item_d, item_e
|
||||
@@ -1,6 +0,0 @@
|
||||
from typing import List
|
||||
|
||||
|
||||
def process_items(items: List[str]):
|
||||
for item in items:
|
||||
print(item)
|
||||
@@ -1,5 +0,0 @@
|
||||
from typing import Set, Tuple
|
||||
|
||||
|
||||
def process_items(items_t: Tuple[int], items_s: Set[bytes]):
|
||||
return items_t, items_s
|
||||
@@ -1,7 +0,0 @@
|
||||
from typing import Dict
|
||||
|
||||
|
||||
def process_items(prices: Dict[str, float]):
|
||||
for item_name, item_price in prices.items():
|
||||
print(item_name)
|
||||
print(item_price)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user