Compare commits

...

21 Commits

Author SHA1 Message Date
Sebastián Ramírez
7372f6ba11 🔖 Release version 0.54.0 2020-04-05 16:50:16 +02:00
Sebastián Ramírez
8d92557e53 📝 Update relase notes 2020-04-05 16:47:33 +02:00
Mickey Pashov
c56342bf79 ✏️ Fix minor grammatical mistakes in the async docs (#1188)
* Fix minor grammatical mistakes in the async docs.

* ✏️ Update wording and clarify with emojis

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-04-05 16:46:22 +02:00
Harsha Laxman
07e094fd50 📝 Add note about Alembic in project generator in SQL docs (#1183)
* Update sql-databases alembic docs

Was helpful to refer to the full-stack project when integrating alembic into my own project

* 📝 Update Alembic note in docs

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-04-05 15:15:39 +02:00
Sebastián Ramírez
1cc30de32f 📝 Update release notes 2020-04-05 15:07:00 +02:00
voegtlel
3397d4d69a Implement response_model_exclude_defaults and response_model_exclude_none (#1166)
* Implemented response_model_exclude_defaults and response_model_exclude_none to be compatible pydantic options.

* 🚚 Rename and invert include_none to exclude_none to keep in sync with Pydantic

Co-authored-by: Lukas Voegtle <lukas.voegtle@sick.de>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-04-05 15:04:46 +02:00
Sebastián Ramírez
766157bfb4 📝 Update release notes 2020-04-05 13:57:45 +02:00
duganchen
d96223460b 📝 Add an example of setting up a test database (#1144)
* Add an example of setting up a test database.

* 📝 Add/update docs for testing a DB with dependency overrides

* 🔧 Update test script, remove line removing test file as it is removed during testing

*  Update testing coverage pragma

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-04-05 13:53:09 +02:00
Sebastián Ramírez
fd99dfc95b 📝 Update release notes 2020-04-04 22:38:17 +02:00
Sebastián Ramírez
10fb7ace04 📝 Update contributing guidelines to review translation PRs (#1215) 2020-04-04 22:36:10 +02:00
Sebastián Ramírez
a1a19b103c 📝 Update release notes 2020-04-04 22:16:12 +02:00
Sebastián Ramírez
5c111caf40 📝 Update release notes 2020-04-04 22:14:55 +02:00
Gao Chao
651ee5e4d2 🎨 Update log style in main page, for GitHub Markdown compatibility (#1200)
* Update README.md

fix string format

* 🎨 Update log style in main page, for GitHub Markdown compatibility

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-04-04 22:13:55 +02:00
Cássio Botaro
c398ac87d9 🙈 Add Python venv "env" to gitignore (#1212) 2020-04-04 22:03:17 +02:00
Cássio Botaro
0a77c613b0 🌐 Add new language on docs: pt (#1210) 2020-04-04 22:01:19 +02:00
Sebastián Ramírez
70bc469373 📝 Update release notes 2020-04-04 21:39:52 +02:00
Sebastián Ramírez
b76334f544 📝 Settings using lru_cache (#1214)
*  Update settings examples to use lru_cache

* 📝 Update docs for Settings, using @lru_cache

* 🎨 Update lru_cache colors to show difference in stored values
2020-04-04 21:39:15 +02:00
Sebastián Ramírez
14b467db06 📝 Update release notes 2020-04-02 07:03:00 +02:00
Camila Gutierrez
3a0c22ce7d 🌐 Translate index to Spanish (#1201) 2020-04-02 07:00:50 +02:00
Sebastián Ramírez
3b7e4e0544 📝 Update release notes 2020-04-02 06:59:19 +02:00
alexmitelman
d4d5b21b2e 📝 Add documentation about settings and env vars (#1118)
* Add doc and example for env var config

* Syntax highlight for .env file

* Add test for configuration docs

* 📝 Update settings docs, add more examples

*  Add tests for settings

* 🚚 Rename "Application Configuration" to "Metadata and Docs URLs"

to disambiguate between that and settings

* 🔥 Remove replaced example file

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-04-02 06:55:20 +02:00
50 changed files with 1617 additions and 216 deletions

1
.gitignore vendored
View File

@@ -14,4 +14,5 @@ test.db
log.txt
Pipfile.lock
env3.*
env
docs_build

View File

@@ -176,11 +176,11 @@ Run the server with:
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<span style="color: green;">INFO</span>: Started reloader process [28720]
<span style="color: green;">INFO</span>: Started server process [28722]
<span style="color: green;">INFO</span>: Waiting for application startup.
<span style="color: green;">INFO</span>: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
</div>

View File

@@ -0,0 +1,380 @@
# Settings and Environment Variables
In many cases your application could need some external settings or configurations, for example secret keys, database credentials, credentials for email services, etc.
Most of these settings are variable (can change), like database URLs. And many could be sensitive, like secrets.
For this reason it's common to provide them in environment variables that are read by the application.
## Environment Variables
!!! tip
If you already know what "environment variables" are and how to use them, feel free to skip to the next section below.
An <a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">environment variable</a> (also known as "env var") is a variable that lives outside of the Python code, in the operating system, and could be read by your Python code (or by other programs as well).
You can create and use environment variables in the shell, without needing Python:
<div class="termy">
```console
// You could create an env var MY_NAME with
$ export MY_NAME="Wade Wilson"
// Then you could use it with other programs, like
$ echo "Hello $MY_NAME"
Hello Wade Wilson
```
</div>
Or in PowerShell in Windows:
<div class="termy">
```console
// Create an env var MY_NAME
$ $Env:MY_NAME = "Wade Wilson"
// Use it with other programs, like
$ echo "Hello $Env:MY_NAME"
Hello Wade Wilson
```
</div>
### Read env vars in Python
You could also create environment variables outside of Python, in the terminal (or with any other method), and then read them in Python.
For example you could have a file `main.py` with:
```Python hl_lines="3"
import os
name = os.getenv("MY_NAME", "World")
print(f"Hello {name} from Python")
```
!!! tip
The second argument to <a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> is the default value to return.
If not provided, it's `None` by default, here we provide `"World"` as the default value to use.
Then you could call that Python program:
<div class="termy">
```console
// Here we don't set the env var yet
$ python main.py
// As we didn't set the env var, we get the default value
Hello World from Python
// But if we create an environment variable first
$ export MY_NAME="Wade Wilson"
// And then call the program again
$ python main.py
// Now it can read the environment variable
Hello Wade Wilson from Python
```
</div>
As environment variables can be set outside of the code, but can be read by the code, and don't have to be stored (committed to `git`) with the rest of the files, it's common to use them for configurations or settings.
You can also create an environment variable only for a specific program invocation, that is only available to that program, and only for its duration.
To do that, create it right before the program itself, on the same line:
<div class="termy">
```console
// Create an env var MY_NAME in line for this program call
$ MY_NAME="Wade Wilson" python main.py
// Now it can read the environment variable
Hello Wade Wilson from Python
// The env var no longer exists afterwards
$ python main.py
Hello World from Python
```
</div>
!!! tip
You can read more about it at <a href="https://12factor.net/config" class="external-link" target="_blank">The Twelve-Factor App: Config</a>.
### Types and validation
These environment variables can only handle text strings, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, as Linux, Windows, macOS).
That means that any value read in Python from an environment variable will be a `str`, and any conversion to a different type or validation has to be done in code.
## Pydantic `Settings`
Fortunately, Pydantic provides a great utility to handle these settings coming from environment variables with <a href="https://pydantic-docs.helpmanual.io/usage/settings/" class="external-link" target="_blank">Pydantic: Settings management</a>.
### Create the `Settings` object
Import `BaseSettings` from Pydantic and create a sub-class, very much like with a Pydantic model.
The same way as with Pydantic models, you declare class attributes with type annotations, and possibly default values.
You can use all the same validation features and tools you use for Pydantic models, like different data types and additional validations with `Field()`.
```Python hl_lines="2 5 6 7 8 11"
{!../../../docs_src/settings/tutorial001.py!}
```
!!! tip
If you want something quick to copy and paste, don't use this example, use the last one below.
Then, when you create an instance of that `Settings` class (in this case, in the `settings` object), Pydantic will read the environment variables in a case-insensitive way, so, an upper-case variable `APP_NAME` will still be read for the attribute `app_name`.
Next it will convert and validate the data. So, when you use that `settings` object, you will have data of the types you declared (e.g. `items_per_user` will be an `int`).
### Use the `settings`
Then you can use the new `settings` object in your application:
```Python hl_lines="18 19 20"
{!../../../docs_src/settings/tutorial001.py!}
```
### Run the server
Next, you would run the server passing the configurations as environment variables, for example you could set an `ADMIN_EMAIL` and `APP_NAME` with:
<div class="termy">
```console
$ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" uvicorn main:app
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
!!! tip
To set multiple env vars for a single command just separate them with a space, and put them all before the command.
And then the `admin_email` setting would be set to `"deadpool@example.com"`.
The `app_name` would be `"ChimichangApp"`.
And the `items_per_user` would keep its default value of `50`.
## Settings in another module
You could put those settings in another module file as you saw in [Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}.
For example, you could have a file `config.py` with:
```Python
{!../../../docs_src/settings/app01/config.py!}
```
And then use it in a file `main.py`:
```Python hl_lines="3 11 12 13"
{!../../../docs_src/settings/app01/main.py!}
```
!!! tip
You would also need a file `__init__.py` as you saw on [Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}.
## Settings in a dependency
In some occasions it might be useful to provide the settings from a dependency, instead of having a global object with `settings` that is used everywhere.
This could be especially useful during testing, as it's very easy to override a dependency with your own custom settings.
### The config file
Coming from the previous example, your `config.py` file could look like:
```Python hl_lines="10"
{!../../../docs_src/settings/app02/config.py!}
```
Notice that now we don't create a default instance `settings = Settings()`.
### The main app file
Now we create a dependency that returns a new `config.Settings()`.
```Python hl_lines="5 11 12"
{!../../../docs_src/settings/app02/main.py!}
```
!!! tip
We'll discuss the `@lru_cache()` in a bit.
For now you can assume `get_settings()` is a normal function.
And then we can require it from the *path operation function* as a dependency and use it anywhere we need it.
```Python hl_lines="16 18 19 20"
{!../../../docs_src/settings/app02/main.py!}
```
### Settings and testing
Then it would be very easy to provide a different settings object during testing by creating a dependency override for `get_settings`:
```Python hl_lines="8 9 12 21"
{!../../../docs_src/settings/app02/test_main.py!}
```
In the dependency override we set a new value for the `admin_email` when creating the new `Settings` object, and then we return that new object.
Then we can test that it is used.
## Reading a `.env` file
If you have many settings that possibly change a lot, maybe in different environments, it might be useful to put them on a file and then read them from it as if they were environment variables.
This practice is common enough that it has a name, these environment variables are commonly placed in a file `.env`, and the file is called a "dotenv".
!!! tip
A file starting with a dot (`.`) is a hidden file in Unix-like systems, like Linux and macOS.
But a dotenv file doesn't really have to have that exact filename.
Pydantic has support for reading from these types of files using an external library. You can read more at <a href="https://pydantic-docs.helpmanual.io/usage/settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic Settings: Dotenv (.env) support</a>.
!!! tip
For this to work, you need to `pip install python-dotenv`.
### The `.env` file
You could have a `.env` file with:
```bash
ADMIN_EMAIL="deadpool@example.com"
APP_NAME="ChimichangApp"
```
### Read settings from `.env`
And then update your `config.py` with:
```Python hl_lines="9 10"
{!../../../docs_src/settings/app03/config.py!}
```
Here we create a class `Config` inside of your Pydantic `Settings` class, and set the `env_file` to the filename with the dotenv file we want to use.
!!! tip
The `Config` class is used just for Pydantic configuration. You can read more at <a href="https://pydantic-docs.helpmanual.io/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>
### Creating the `Settings` only once with `lru_cache`
Reading a file from disk is normally a costly (slow) operation, so you probably want to do it only once and then re-use the same settings object, instead of reading it for each request.
But every time we do:
```Python
config.Settings()
```
a new `Settings` object would be created, and at creation it would read the `.env` file again.
If the dependency function was just like:
```Python
def get_settings():
return config.Settings()
```
we would create that object for each request, and we would be reading the `.env` file for each request. ⚠️
But as we are using the `@lru_cache()` decorator on top, the `Settings` object will be created only once, the first time it's called. ✔️
```Python hl_lines="1 10"
{!../../../docs_src/settings/app03/main.py!}
```
Then for any subsequent calls of `get_settings()` in the dependencies for the next requests, instead of executing the internal code of `get_settings()` and creating a new `Settings` object, it will return the same object that was returned on the first call, again and again.
#### `lru_cache` Technical Details
`@lru_cache()` modifies the function it decorates to return the same value that was returned the first time, instead of computing it again, executing the code of the function every time.
So, the function below it will be executed once for each combination of arguments. And then the values returned by each of those combinations of arguments will be used again and again whenever the function is called with exactly the same combination of arguments.
For example, if you have a function:
```Python
@lru_cache()
def say_hi(name: str, salutation: str = "Ms."):
return f"Hello {salutation} {name}"
```
your program could execute like this:
```mermaid
sequenceDiagram
participant code as Code
participant function as say_hi()
participant execute as Execute function
rect rgba(0, 255, 0, .1)
code ->> function: say_hi(name="Camila")
function ->> execute: execute function code
execute ->> code: return the result
end
rect rgba(0, 255, 255, .1)
code ->> function: say_hi(name="Camila")
function ->> code: return stored result
end
rect rgba(0, 255, 0, .1)
code ->> function: say_hi(name="Rick")
function ->> execute: execute function code
execute ->> code: return the result
end
rect rgba(0, 255, 0, .1)
code ->> function: say_hi(name="Rick", salutation="Mr.")
function ->> execute: execute function code
execute ->> code: return the result
end
rect rgba(0, 255, 255, .1)
code ->> function: say_hi(name="Rick")
function ->> code: return stored result
end
rect rgba(0, 255, 255, .1)
code ->> function: say_hi(name="Camila")
function ->> code: return stored result
end
```
In the case of our dependency `get_settings()`, the function doesn't even take any arguments, so it always returns the same value.
That way, it behaves almost as if it was just a global variable. But as it uses a dependency function, then we can override it easily for testing.
`@lru_cache()` is part of `functools` which is part of Python's standard library, you can read more about it in the <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">Python docs for `@lru_cache()`</a>.
## Recap
You can use Pydantic Settings to handle the settings or configurations for your application, with all the power of Pydantic models.
* By using a dependency you can simplify testing.
* You can use `.env` files with it.
* Using `@lru_cache()` lets you avoid reading the dotenv file again and again for each request, while allowing you to override it during testing.

View File

@@ -0,0 +1,95 @@
# Testing a Database
You can use the same dependency overrides from [Testing Dependencies with Overrides](testing-dependencies.md){.internal-link target=_blank} to alter a database for testing.
You could want to set up a different database for testing, rollback the data after the tests, pre-fill it with some testing data, etc.
The main idea is exactly the same you saw in that previous chapter.
## Add tests for the SQL app
Let's update the example from [SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank} to use a testing database.
All the app code is the same, you can go back to that chapter check how it was.
The only changes here are in the new testing file.
Your normal dependency `get_db()` would return a database session.
In the test, you could use a dependency override to return your *custom* database session instead of the one that would be used normally.
In this example we'll create a temporary database only for the tests.
## File structure
We create a new file at `sql_app/tests/test_sql_app.py`.
So the new file structure looks like:
``` hl_lines="9 10 11"
.
└── sql_app
├── __init__.py
├── crud.py
├── database.py
├── main.py
├── models.py
├── schemas.py
└── tests
├── __init__.py
└── test_sql_app.py
```
## Create the new database session
First, we create a new database session with the new database.
For the tests we'll use a file `test.db` instead of `sql_app.db`.
But the rest of the session code is more or less the same, we just copy it.
```Python hl_lines="8 9 10 11 12 13"
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
```
!!! tip
You could reduce duplication in that code by putting it in a function and using it from both `database.py` and `tests/test_sql_app.py`.
For simplicity and to focus on the specific testing code, we are just copying it.
## Create the database
Because now we are going to use a new database in a new file, we need to make sure we create the database with:
```Python
Base.metadata.create_all(bind=engine)
```
That is normally called in `main.py`, but the line in `main.py` uses the database file `sql_app.db`, and we need to make sure we create `test.db` for the tests.
So we add that line here, with the new file.
```Python hl_lines="16"
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
```
## Dependency override
Now we create the dependency override and add it to the overrides for our app.
```Python hl_lines="19 20 21 22 23 24 27"
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
```
!!! tip
The code for `override_get_db()` is almost exactly the same as for `get_db()`, but in `override_get_db()` we use the `TestingSessionLocal` for the testing database instead.
## Test the app
Then we can just test the app as normally.
```Python hl_lines="32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47"
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
```
And all the modifications we made in the database during the tests will be in the `test.db` database instead of the main `sql_app.db`.

View File

@@ -20,18 +20,6 @@ You probably want to test the external provider once, but not necessarily call i
In this case, you can override the dependency that calls that provider, and use a custom dependency that returns a mock user, only for your tests.
### Use case: testing database
Other example could be that you are using a specific database only for testing.
Your normal dependency would return a database session.
But then, after each test, you could want to rollback all the operations or remove data.
Or you could want to alter the data before the tests run, etc.
In this case, you could use a dependency override to return your *custom* database session instead of the one that would be used normally.
### Use the `app.dependency_overrides` attribute
For these cases, your **FastAPI** application has an attribute `app.dependency_overrides`, it is a simple `dict`.

View File

@@ -63,13 +63,13 @@ Let's see that phrase by parts in the sections below, below:
## Asynchronous Code
Asynchronous code just means that the language has a way to tell the computer / program that at some point in the code, he will have to wait for *something else* to finish somewhere else. Let's say that *something else* is called "slow-file".
Asynchronous code just means that the language 💬 has a way to tell the computer / program 🤖 that at some point in the code, it 🤖 will have to wait for *something else* to finish somewhere else. Let's say that *something else* is called "slow-file" 📝.
So, during that time, the computer can go and do some other work, while "slow-file" finishes.
So, during that time, the computer can go and do some other work, while "slow-file" 📝 finishes.
Then the computer / program will come back every time it has a chance because it's waiting again, or whenever he finished all the work he had at that point. And it will see if any of the tasks he was waiting for has already finished doing whatever it had to do.
Then the computer / program 🤖 will come back every time it has a chance because it's waiting again, or whenever it 🤖 finished all the work it had at that point. And it 🤖 will see if any of the tasks it was waiting for have already finished, doing whatever it had to do.
And then it takes the first task to finish (let's say, our "slow-file") and continues whatever it had to do with it.
Next, it 🤖 takes the first task to finish (let's say, our "slow-file" 📝) and continues whatever it had to do with it.
That "wait for something else" normally refers to <abbr title="Input and Output">I/O</abbr> operations that are relatively "slow" (compared to the speed of the processor and the RAM memory), like waiting for:
@@ -82,7 +82,7 @@ That "wait for something else" normally refers to <abbr title="Input and Output"
* a database query to return the results
* etc.
As the execution time is consumed mostly by waiting for <abbr title="Input and Output">I/O</abbr> operations, so they call them "I/O bound".
As the execution time is consumed mostly by waiting for <abbr title="Input and Output">I/O</abbr> operations, they call them "I/O bound" operations.
It's called "asynchronous" because the computer / program doesn't have to be "synchronized" with the slow task, waiting for the exact moment that the task finishes, while doing nothing, to be able to take the task result and continue the work.
@@ -114,7 +114,7 @@ The cashier gives you the number of your turn.
While you are waiting, you go with your crush and pick a table, you sit and talk with your crush for a long time (as your burgers are very fancy and take some time to prepare).
As you are seating on the table with your crush, while you wait for the burgers, you can spend that time admiring how awesome, cute and smart your crush is.
As you are sitting on the table with your crush, while you wait for the burgers, you can spend that time admiring how awesome, cute and smart your crush is.
While waiting and talking to your crush, from time to time, you check the number displayed on the counter to see if it's your turn already.
@@ -132,7 +132,7 @@ Then, when it's your turn, you do actual "productive" work, you process the menu
But then, even though you still don't have your burgers, your work with the cashier is "on pause", because you have to wait for your burgers to be ready.
But as you go away from the counter and seat on the table with a number for your turn, you can switch your attention to your crush, and "work" on that. Then you are again doing something very "productive", as is flirting with your crush.
But as you go away from the counter and sit on the table with a number for your turn, you can switch your attention to your crush, and "work" on that. Then you are again doing something very "productive", as is flirting with your crush.
Then the cashier says "I'm finished with doing the burgers" by putting your number on the counter display, but you don't jump like crazy immediately when the displayed number changes to your turn number. You know no one will steal your burgers because you have the number of your turn, and they have theirs.

View File

@@ -257,7 +257,16 @@ Here are the steps to help with translations.
#### Tips and guidelines
* Add a single Pull Request per page translated. That will make it much easier for others to review it.
* Check the currently <a href="https://github.com/tiangolo/fastapi/pulls" class="external-link" target="_blank">existing pull requests</a> for your language and add reviews requesting changes or approving them.
!!! tip
You can <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request" class="external-link" target="_blank">add comments with change suggestions</a> to existing pull requests.
Check the docs about <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews" class="external-link" target="_blank">adding a pull request review</a> to approve it or request changes.
* Check in the <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">issues</a> to see if there's one coordinating translations for your language.
* Add a single pull request per page translated. That will make it much easier for others to review it.
For the languages I don't speak, I'll wait for several others to review the translation before merging.
@@ -385,6 +394,11 @@ Updating en
Now you can check in your code editor the newly created directory `docs/ht/`.
!!! tip
Create a first pull request with just this, to set up the configuration for the new language, before adding translations.
That way others can help with other pages while you work on the first one. 🚀
Start by translating the main page, `docs/ht/index.md`.
Then you can continue with the previous instructions, for an "Existing Language".

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -176,11 +176,11 @@ Run the server with:
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<span style="color: green;">INFO</span>: Started reloader process [28720]
<span style="color: green;">INFO</span>: Started server process [28722]
<span style="color: green;">INFO</span>: Waiting for application startup.
<span style="color: green;">INFO</span>: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
</div>

View File

@@ -2,6 +2,21 @@
## Latest changes
## 0.54.0
* Fix grammatical mistakes in async docs. PR [#1188](https://github.com/tiangolo/fastapi/pull/1188) by [@mickeypash](https://github.com/mickeypash).
* Add support for `response_model_exclude_defaults` and `response_model_exclude_none`:
* Deprecate the parameter `include_none` in `jsonable_encoder` and add the inverted `exclude_none`, to keep in sync with Pydantic.
* PR [#1166](https://github.com/tiangolo/fastapi/pull/1166) by [@voegtlel](https://github.com/voegtlel).
* Add example about [Testing a Database](https://fastapi.tiangolo.com/advanced/testing-database/). Initial PR [#1144](https://github.com/tiangolo/fastapi/pull/1144) by [@duganchen](https://github.com/duganchen).
* Update docs for [Development - Contributing: Translations](https://fastapi.tiangolo.com/contributing/#translations) including note about reviewing translation PRs. [#1215](https://github.com/tiangolo/fastapi/pull/1215).
* Update log style in README.md for GitHub Markdown compatibility. PR [#1200](https://github.com/tiangolo/fastapi/pull/1200) by [#geekgao](https://github.com/geekgao).
* Add Python venv `env` to `.gitignore`. PR [#1212](https://github.com/tiangolo/fastapi/pull/1212) by [@cassiobotaro](https://github.com/cassiobotaro).
* Start Portuguese translations. PR [#1210](https://github.com/tiangolo/fastapi/pull/1210) by [@cassiobotaro](https://github.com/cassiobotaro).
* Update docs for Pydantic's `Settings` using a dependency with `@lru_cache()`. PR [#1214](https://github.com/tiangolo/fastapi/pull/1214).
* Add first translation to Spanish [FastAPI](https://fastapi.tiangolo.com/es/). PR [#1201](https://github.com/tiangolo/fastapi/pull/1201) by [@mariacamilagl](https://github.com/mariacamilagl).
* Add docs about [Settings and Environment Variables](https://fastapi.tiangolo.com/advanced/settings/). Initial PR [1118](https://github.com/tiangolo/fastapi/pull/1118) by [@alexmitelman](https://github.com/alexmitelman).
## 0.53.2
* Fix automatic embedding of body fields for dependencies and sub-dependencies. Original PR [#1079](https://github.com/tiangolo/fastapi/pull/1079) by [@Toad2186](https://github.com/Toad2186).

View File

@@ -1,25 +1,25 @@
# Application Configuration
# Metadata and Docs URLs
There are several things that you can configure in your FastAPI application.
You can customize several metadata configurations in your **FastAPI** application.
## Title, description, and version
You can set the:
* Title: used as your API's title/name, in OpenAPI and the automatic API docs UIs.
* Description: the description of your API, in OpenAPI and the automatic API docs UIs.
* Version: the version of your API, e.g. `v2` or `2.5.0`.
* **Title**: used as your API's title/name, in OpenAPI and the automatic API docs UIs.
* **Description**: the description of your API, in OpenAPI and the automatic API docs UIs.
* **Version**: the version of your API, e.g. `v2` or `2.5.0`.
* Useful for example if you had a previous version of the application, also using OpenAPI.
To set them, use the parameters `title`, `description`, and `version`:
```Python hl_lines="4 5 6"
{!../../../docs_src/application_configuration/tutorial001.py!}
{!../../../docs_src/metadata/tutorial001.py!}
```
With this configuration, the automatic API docs would look like:
<img src="/img/tutorial/application-configuration/image01.png">
<img src="/img/tutorial/metadata/image01.png">
## OpenAPI URL
@@ -30,7 +30,7 @@ But you can configure it with the parameter `openapi_url`.
For example, to set it to be served at `/api/v1/openapi.json`:
```Python hl_lines="3"
{!../../../docs_src/application_configuration/tutorial002.py!}
{!../../../docs_src/metadata/tutorial002.py!}
```
If you want to disable the OpenAPI schema completely you can set `openapi_url=None`.
@@ -49,5 +49,5 @@ You can configure the two documentation user interfaces included:
For example, to set Swagger UI to be served at `/documentation` and disable ReDoc:
```Python hl_lines="3"
{!../../../docs_src/application_configuration/tutorial003.py!}
{!../../../docs_src/metadata/tutorial003.py!}
```

View File

@@ -98,9 +98,9 @@ Let's refer to the file `sql_app/database.py`.
In this example, we are "connecting" to a SQLite database (opening a file with the SQLite database).
The file will be located at the same directory in the file `test.db`.
The file will be located at the same directory in the file `sql_app.db`.
That's why the last part is `./test.db`.
That's why the last part is `./sql_app.db`.
If you were using a **PostgreSQL** database instead, you would just have to uncomment the line:
@@ -437,6 +437,8 @@ And you would also use Alembic for "migrations" (that's its main job).
A "migration" is the set of steps needed whenever you change the structure of your SQLAlchemy models, add a new attribute, etc. to replicate those changes in the database, add a new column, a new table, etc.
You can find an example of Alembic in a FastAPI project in the templates from [Project Generation - Template](../project-generation.md){.internal-link target=_blank}. Specifically in <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql/tree/master/%7B%7Bcookiecutter.project_slug%7D%7D/backend/app/alembic/" class="external-link" target="_blank">the `alembic` directory in the source code</a>.
### Create a dependency
!!! info

View File

@@ -20,6 +20,7 @@ nav:
- Languages:
- en: /
- es: /es/
- pt: /pt/
- zh: /zh/
- features.md
- python-types.md
@@ -65,7 +66,7 @@ nav:
- tutorial/sql-databases.md
- tutorial/bigger-applications.md
- tutorial/background-tasks.md
- tutorial/application-configuration.md
- tutorial/metadata.md
- tutorial/static-files.md
- tutorial/testing.md
- tutorial/debugging.md
@@ -98,6 +99,8 @@ nav:
- advanced/testing-websockets.md
- advanced/testing-events.md
- advanced/testing-dependencies.md
- advanced/testing-database.md
- advanced/settings.md
- advanced/extending-openapi.md
- advanced/openapi-callbacks.md
- advanced/wsgi.md

View File

@@ -2,7 +2,7 @@
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
</p>
<p align="center">
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
<em>FastAPI framework, alto desempeño, fácil de aprender, rápido de programar, listo para producción</em>
</p>
<p align="center">
<a href="https://travis-ci.com/tiangolo/fastapi" target="_blank">
@@ -21,29 +21,28 @@
---
**Documentation**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
**Documentación**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
**Source Code**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>
**Código Fuente**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>
---
FastAPI es un web framework moderno y rápido (de alto rendimiento) para construir APIs con Python 3.6+ basado en las anotaciones de tipos estándar de Python.
FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
Sus características principales son:
The key features are:
* **Rapidez**: Alto rendimiento, a la par con **NodeJS** y **Go** (gracias a Starlette y Pydantic). [Uno de los frameworks de Python más rápidos](#rendimiento).
* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
* **Rápido de programar**: Incrementa la velocidad de desarrollo entre 200% y 300% *.
* **Menos errores**: Reduce los errores humanos (de programador) aproximadamente un 40% *.
* **Intuitivo**: Gran soporte en los editores con <abbr title="conocido en inglés como auto-complete, autocompletion, IntelliSense, completion">auto completado</abbr> en todas partes. Gasta menos tiempo <abbr title="buscando y corrigiendo errores">debugging</abbr>.
* **Fácil**: Está diseñado para ser fácil de usar y aprender. Gastando menos tiempo leyendo documentación.
* **Corto**: Minimiza la duplicación de código. Múltiples funcionalidades con cada declaración de parámetros. Menos errores.
* **Robusto**: Crea código listo para producción con documentación automática interactiva.
* **Basado en estándares**: Basado y totalmente compatible con los estándares abiertos para APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (conocido previamente como Swagger) y <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
* **Fast to code**: Increase the speed to develop features by about 200% to 300% *.
* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
* **Intuitive**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> everywhere. Less time debugging.
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
* **Robust**: Get production-ready code. With automatic interactive documentation.
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
<small>* Esta estimación está basada en pruebas con un equipo de desarrollo interno contruyendo aplicaciones listas para producción.</small>
<small>* estimation based on tests on an internal development team, building production applications.</small>
## Opinions
## Opiniones
"*[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products.*"
@@ -77,24 +76,24 @@ The key features are:
---
## **Typer**, the FastAPI of CLIs
## **Typer**, el FastAPI de las CLIs
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
If you are building a <abbr title="Command Line Interface">CLI</abbr> app to be used in the terminal instead of a web API, check out <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
Si estás construyendo un app de <abbr title="Interfaz de línea de comandos en español">CLI</abbr> para ser usada en la terminal en vez de una API web, fíjate en <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀
**Typer** es el hermano menor de FastAPI. La intención es que sea el **FastAPI de las CLIs**. ⌨️ 🚀
## Requirements
## Requisitos
Python 3.6+
FastAPI stands on the shoulders of giants:
FastAPI está sobre los hombros de gigantes:
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> for the web parts.
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> for the data parts.
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> para las partes web.
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> para las partes de datos.
## Installation
## Instalación
<div class="termy">
@@ -106,7 +105,7 @@ $ pip install fastapi
</div>
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
También vas a necesitar un servidor ASGI para producción cómo <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> o <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
<div class="termy">
@@ -118,11 +117,11 @@ $ pip install uvicorn
</div>
## Example
## Ejemplo
### Create it
### Créalo
* Create a file `main.py` with:
* Crea un archivo `main.py` con:
```Python
from fastapi import FastAPI
@@ -141,9 +140,9 @@ def read_item(item_id: int, q: str = None):
```
<details markdown="1">
<summary>Or use <code>async def</code>...</summary>
<summary>O usa <code>async def</code>...</summary>
If your code uses `async` / `await`, use `async def`:
Si tu código usa `async` / `await`, usa `async def`:
```Python hl_lines="7 12"
from fastapi import FastAPI
@@ -161,79 +160,79 @@ async def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
```
**Note**:
**Nota**:
If you don't know, check the _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
Si no lo sabes, revisa la sección _"¿Con prisa?"_ sobre <a href="https://fastapi.tiangolo.com/es/async/#con-prisa" target="_blank">`async` y `await` en la documentación</a>.
</details>
### Run it
### Córrelo
Run the server with:
Corre el servidor con:
<div class="termy">
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<span style="color: green;">INFO</span>: Started reloader process [28720]
<span style="color: green;">INFO</span>: Started server process [28722]
<span style="color: green;">INFO</span>: Waiting for application startup.
<span style="color: green;">INFO</span>: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
</div>
<details markdown="1">
<summary>About the command <code>uvicorn main:app --reload</code>...</summary>
<summary>Sobre el comando <code>uvicorn main:app --reload</code>...</summary>
The command `uvicorn main:app` refers to:
El comando `uvicorn main:app` se refiere a:
* `main`: the file `main.py` (the Python "module").
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
* `--reload`: make the server restart after code changes. Only do this for development.
* `main`: el archivo `main.py` (el"modulo" de Python).
* `app`: el objeto creado dentro de `main.py` con la línea `app = FastAPI()`.
* `--reload`: hace que el servidor se reinicie después de cambios en el código. Esta opción solo debe ser usada en desarrollo.
</details>
### Check it
### Revísalo
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
Abre tu navegador en <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
You will see the JSON response as:
Verás la respuesta de JSON cómo:
```JSON
{"item_id": 5, "q": "somequery"}
```
You already created an API that:
Ya creaste una API que:
* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.
* Both _paths_ take `GET` <em>operations</em> (also known as HTTP _methods_).
* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.
* Recibe HTTP requests en los _paths_ `/` y `/items/{item_id}`.
* Ambos _paths_ toman <em>operaciones</em> `GET` (también conocido como HTTP _methods_).
* El _path_ `/items/{item_id}` tiene un _path parameter_ `item_id` que debería ser un `int`.
* El _path_ `/items/{item_id}` tiene un `str` _query parameter_ `q` opcional.
### Interactive API docs
### Documentación interactiva de APIs
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Ahora ve a <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
Verás la documentación automática e interactiva de la API (proveída por <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Alternative API docs
### Documentación alternativa de la API
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
Ahora, ve a <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
Ahora verás la documentación automática alternativa (proveída por <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## Example upgrade
## Mejora al ejemplo
Now modify the file `main.py` to receive a body from a `PUT` request.
Ahora modifica el archivo `main.py` para recibir un <abbr title="cuerpo del mensaje HTTP">body</abbr> del `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
Declara el body usando las declaraciones de tipo estándares de Python gracias a Pydantic.
```Python hl_lines="2 7 8 9 10 23 24 25"
from fastapi import FastAPI
@@ -263,175 +262,175 @@ def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
The server should reload automatically (because you added `--reload` to the `uvicorn` command above).
El servidor debería recargar automáticamente (porque añadiste `--reload` al comando `uvicorn` que está más arriba).
### Interactive API docs upgrade
### Mejora a la documentación interactiva de APIs
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Ahora ve a <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
* The interactive API documentation will be automatically updated, including the new body:
* La documentación interactiva de la API se actualizará automáticamente, incluyendo el nuevo body:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API:
* Haz clíck en el botón de "Try it out" que te permite llenar los parámetros e interactuar directamente con la API:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)
* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:
* Luego haz clíck en el botón de "Execute". La interfaz de usuario se comunicará con tu API, enviará los parámetros y recibirá los resultados para mostrarlos en pantalla:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### Alternative API docs upgrade
### Mejora a la documentación alternativa de la API
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
Ahora, ve a <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
* The alternative documentation will also reflect the new query parameter and body:
* La documentación alternativa también reflejará el nuevo parámetro de query y el body:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Recap
### Resumen
In summary, you declare **once** the types of parameters, body, etc. as function parameters.
En resumen, declaras los tipos de parámetros, body, etc. **una vez** como parámetros de la función.
You do that with standard modern Python types.
Lo haces con tipos modernos estándar de Python.
You don't have to learn a new syntax, the methods or classes of a specific library, etc.
No tienes que aprender una sintáxis nueva, los métodos o clases de una library específica, etc.
Just standard **Python 3.6+**.
Solo **Python 3.6+** estándar.
For example, for an `int`:
Por ejemplo, para un `int`:
```Python
item_id: int
```
or for a more complex `Item` model:
o para un modelo más complejo de `Item`:
```Python
item: Item
```
...and with that single declaration you get:
...y con esa única declaración obtienes:
* Editor support, including:
* Completion.
* Type checks.
* Validation of data:
* Automatic and clear errors when the data is invalid.
* Validation even for deeply nested JSON objects.
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of input data: coming from the network to Python data and types. Reading from:
* Soporte del editor incluyendo:
* Auto completado.
* Anotaciones de tipos.
* Validación de datos:
* Errores automáticos y claros cuándo los datos son inválidos.
* Validación, incluso para objetos JSON profundamente anidados.
* <abbr title="en inglés: serialization, parsing, marshalling">Conversión</abbr> de datos de input: viniendo de la red a datos y tipos de Python. Leyendo desde:
* JSON.
* Path parameters.
* Query parameters.
* Cookies.
* Headers.
* Forms.
* Files.
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of output data: converting from Python data and types to network data (as JSON):
* Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
* `datetime` objects.
* `UUID` objects.
* Database models.
* ...and many more.
* Automatic interactive API documentation, including 2 alternative user interfaces:
* Formularios.
* Archivos.
* <abbr title="en inglés: serialization, parsing, marshalling">Conversión</abbr> de datos de output: convirtiendo de datos y tipos de Python a datos para la red (como JSON):
* Convertir tipos de Python (`str`, `int`, `float`, `bool`, `list`, etc).
* Objetos `datetime`.
* Objetos `UUID`.
* Modelos de bases de datos.
* ...y muchos más.
* Documentación automática e interactiva incluyendo 2 interfaces de usuario alternativas:
* Swagger UI.
* ReDoc.
---
Coming back to the previous code example, **FastAPI** will:
Volviendo al ejemplo de código anterior, **FastAPI** va a:
* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.
* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.
* If it is not, the client will see a useful, clear error.
* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.
* As the `q` parameter is declared with `= None`, it is optional.
* Without the `None` it would be required (as is the body in the case with `PUT`).
* For `PUT` requests to `/items/{item_id}`, Read the body as JSON:
* Check that it has a required attribute `name` that should be a `str`.
* Check that it has a required attribute `price` that has to be a `float`.
* Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
* All this would also work for deeply nested JSON objects.
* Convert from and to JSON automatically.
* Document everything with OpenAPI, that can be used by:
* Interactive documentation systems.
* Automatic client code generation systems, for many languages.
* Provide 2 interactive documentation web interfaces directly.
* Validar que existe un `item_id` en el path para requests usando `GET` y `PUT`.
* Validar que el `item_id` es del tipo `int` para requests de tipo `GET` y `PUT`.
* Si no lo es, el cliente verá un mensaje de error útil y claro.
* Revisar si existe un query parameter opcional llamado `q` (cómo en `http://127.0.0.1:8000/items/foo?q=somequery`) para requests de tipo `GET`.
* Como el parámetro `q` fue declarado con `= None` es opcional.
* Sin el `None` sería obligatorio (cómo lo es el body en el caso con `PUT`).
* Para requests de tipo `PUT` a `/items/{item_id}` leer el body como JSON:
* Revisar si tiene un atributo requerido `name` que debe ser un `str`.
* Revisar si tiene un atributo requerido `price` que debe ser un `float`.
* Revisar si tiene un atributo opcional `is_offer`, que debe ser un `bool`si está presente.
* Todo esto funcionaría para objetos JSON profundamente anidados.
* Convertir de y a JSON automáticamente.
* Documentar todo con OpenAPI que puede ser usado por:
* Sistemas de documentación interactiva.
* Sistemas de generación automática de código de cliente para muchos lenguajes.
* Proveer directamente 2 interfaces de documentación web interactivas.
---
We just scratched the surface, but you already get the idea of how it all works.
Hasta ahora, escasamente vimos lo básico pero ya tienes una idea de cómo funciona.
Try changing the line with:
Intenta cambiando la línea a:
```Python
return {"item_name": item.name, "item_id": item_id}
```
...from:
...de:
```Python
... "item_name": item.name ...
```
...to:
...a:
```Python
... "item_price": item.price ...
```
...and see how your editor will auto-complete the attributes and know their types:
... y mira como el editor va a auto-completar los atributos y sabrá sus tipos:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
![soporte de editor](https://fastapi.tiangolo.com/img/vscode-completion.png)
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - User Guide</a>.
Para un ejemplo más completo que incluye más características ve el <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - Guía de Usuario</a>.
**Spoiler alert**: the tutorial - user guide includes:
**Spoiler alert**: el Tutorial - Guía de Usuario incluye:
* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
* How to set **validation constraints** as `maximum_length` or `regex`.
* A very powerful and easy to use **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
* Many extra features (thanks to Starlette) as:
* Declaración de **parámetros** en otros lugares diferentes cómo los: **headers**, **cookies**, **formularios** y **archivos**.
* Cómo agregar **requisitos de validación** cómo `maximum_length` o `regex`.
* Un sistema de **<abbr title="también conocido en inglés cómo: components, resources, providers, services, injectables">Dependency Injection</abbr>** poderoso y fácil de usar.
* Seguridad y autenticación incluyendo soporte para **OAuth2** con **JWT tokens** y **HTTP Basic** auth.
* Técnicas más avanzadas, pero igual de fáciles, para declarar **modelos de JSON profundamente anidados** (gracias a Pydantic).
* Muchas características extra (gracias a Starlette) como:
* **WebSockets**
* **GraphQL**
* extremely easy tests based on `requests` and `pytest`
* pruebas extremadamente fáciles con `requests` y `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
* ...y mucho más.
## Performance
## Rendimiento
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
Benchmarks independientes de TechEmpower muestran que aplicaciones de **FastAPI** corriendo con Uvicorn cómo <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">uno de los frameworks de Python más rápidos</a>, únicamente debajo de Starlette y Uvicorn (usados internamente por FastAPI). (*)
To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
Para entender más al respecto revisa la sección <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
## Optional Dependencies
## Dependencias Opcionales
Used by Pydantic:
Usadas por Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - para <abbr title="convertir el string que viene de un HTTP request a datos de Python">"parsing"</abbr> de JSON más rápido.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - para validación de emails.
Used by Starlette:
Usados por Starlette:
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - Required for `GraphQLApp` support.
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Required if you want to use `UJSONResponse`.
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Requerido si quieres usar el `TestClient`.
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Requerido si quieres usar `FileResponse` o `StaticFiles`.
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Requerido si quieres usar la configuración por defecto de templates.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Requerido si quieres dar soporte a <abbr title="convertir el string que viene de un HTTP request a datos de Python">"parsing"</abbr> de formularios, con `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Requerido para dar soporte a `SessionMiddleware`.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Requerido para dar soporte al `SchemaGenerator` de Starlette (probablemente no lo necesites con FastAPI).
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - Requerido para dar soporte a `GraphQLApp`.
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Requerido si quieres usar `UJSONResponse`.
Used by FastAPI / Starlette:
Usado por FastAPI / Starlette:
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Required if you want to use `ORJSONResponse`.
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - para el servidor que carga y sirve tu aplicación.
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Requerido si quieres usar `ORJSONResponse`.
You can install all of these with `pip install fastapi[all]`.
Puedes instalarlos con `pip install fastapi[all]`.
## License
## Licencia
This project is licensed under the terms of the MIT license.
Este proyecto está licenciado bajo los términos de la licencia del MIT.

View File

@@ -20,6 +20,7 @@ nav:
- Languages:
- en: /
- es: /es/
- pt: /pt/
- zh: /zh/
markdown_extensions:
- toc:

441
docs/pt/docs/index.md Normal file
View File

@@ -0,0 +1,441 @@
{!../../../docs/missing-translation.md!}
<p align="center">
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
</p>
<p align="center">
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
</p>
<p align="center">
<a href="https://travis-ci.com/tiangolo/fastapi" target="_blank">
<img src="https://travis-ci.com/tiangolo/fastapi.svg?branch=master" alt="Build Status">
</a>
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
<img src="https://img.shields.io/codecov/c/github/tiangolo/fastapi" alt="Coverage">
</a>
<a href="https://pypi.org/project/fastapi" target="_blank">
<img src="https://badge.fury.io/py/fastapi.svg" alt="Package version">
</a>
<a href="https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank">
<img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Join the chat at https://gitter.im/tiangolo/fastapi">
</a>
</p>
---
**Documentation**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
**Source Code**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>
---
FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
The key features are:
* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
* **Fast to code**: Increase the speed to develop features by about 200% to 300% *.
* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
* **Intuitive**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> everywhere. Less time debugging.
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
* **Robust**: Get production-ready code. With automatic interactive documentation.
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
<small>* estimation based on tests on an internal development team, building production applications.</small>
## Opinions
"*[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products.*"
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
---
"*Im over the moon excited about **FastAPI**. Its so fun!*"
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
---
"*Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that.*"
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
"*If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]*"
"*We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]*"
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
---
"*We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]*"
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
---
## **Typer**, the FastAPI of CLIs
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
If you are building a <abbr title="Command Line Interface">CLI</abbr> app to be used in the terminal instead of a web API, check out <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀
## Requirements
Python 3.6+
FastAPI stands on the shoulders of giants:
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> for the web parts.
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> for the data parts.
## Installation
<div class="termy">
```console
$ pip install fastapi
---> 100%
```
</div>
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
<div class="termy">
```console
$ pip install uvicorn
---> 100%
```
</div>
## Example
### Create it
* Create a file `main.py` with:
```Python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
```
<details markdown="1">
<summary>Or use <code>async def</code>...</summary>
If your code uses `async` / `await`, use `async def`:
```Python hl_lines="7 12"
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
```
**Note**:
If you don't know, check the _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
</details>
### Run it
Run the server with:
<div class="termy">
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<span style="color: green;">INFO</span>: Started reloader process [28720]
<span style="color: green;">INFO</span>: Started server process [28722]
<span style="color: green;">INFO</span>: Waiting for application startup.
<span style="color: green;">INFO</span>: Application startup complete.
```
</div>
<details markdown="1">
<summary>About the command <code>uvicorn main:app --reload</code>...</summary>
The command `uvicorn main:app` refers to:
* `main`: the file `main.py` (the Python "module").
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
* `--reload`: make the server restart after code changes. Only do this for development.
</details>
### Check it
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
You will see the JSON response as:
```JSON
{"item_id": 5, "q": "somequery"}
```
You already created an API that:
* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.
* Both _paths_ take `GET` <em>operations</em> (also known as HTTP _methods_).
* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.
### Interactive API docs
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Alternative API docs
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## Example upgrade
Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="2 7 8 9 10 23 24 25"
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool = None
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
The server should reload automatically (because you added `--reload` to the `uvicorn` command above).
### Interactive API docs upgrade
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
* The interactive API documentation will be automatically updated, including the new body:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)
* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### Alternative API docs upgrade
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
* The alternative documentation will also reflect the new query parameter and body:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Recap
In summary, you declare **once** the types of parameters, body, etc. as function parameters.
You do that with standard modern Python types.
You don't have to learn a new syntax, the methods or classes of a specific library, etc.
Just standard **Python 3.6+**.
For example, for an `int`:
```Python
item_id: int
```
or for a more complex `Item` model:
```Python
item: Item
```
...and with that single declaration you get:
* Editor support, including:
* Completion.
* Type checks.
* Validation of data:
* Automatic and clear errors when the data is invalid.
* Validation even for deeply nested JSON objects.
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of input data: coming from the network to Python data and types. Reading from:
* JSON.
* Path parameters.
* Query parameters.
* Cookies.
* Headers.
* Forms.
* Files.
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of output data: converting from Python data and types to network data (as JSON):
* Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
* `datetime` objects.
* `UUID` objects.
* Database models.
* ...and many more.
* Automatic interactive API documentation, including 2 alternative user interfaces:
* Swagger UI.
* ReDoc.
---
Coming back to the previous code example, **FastAPI** will:
* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.
* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.
* If it is not, the client will see a useful, clear error.
* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.
* As the `q` parameter is declared with `= None`, it is optional.
* Without the `None` it would be required (as is the body in the case with `PUT`).
* For `PUT` requests to `/items/{item_id}`, Read the body as JSON:
* Check that it has a required attribute `name` that should be a `str`.
* Check that it has a required attribute `price` that has to be a `float`.
* Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
* All this would also work for deeply nested JSON objects.
* Convert from and to JSON automatically.
* Document everything with OpenAPI, that can be used by:
* Interactive documentation systems.
* Automatic client code generation systems, for many languages.
* Provide 2 interactive documentation web interfaces directly.
---
We just scratched the surface, but you already get the idea of how it all works.
Try changing the line with:
```Python
return {"item_name": item.name, "item_id": item_id}
```
...from:
```Python
... "item_name": item.name ...
```
...to:
```Python
... "item_price": item.price ...
```
...and see how your editor will auto-complete the attributes and know their types:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - User Guide</a>.
**Spoiler alert**: the tutorial - user guide includes:
* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
* How to set **validation constraints** as `maximum_length` or `regex`.
* A very powerful and easy to use **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* **GraphQL**
* extremely easy tests based on `requests` and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
## Performance
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
## Optional Dependencies
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - Required for `GraphQLApp` support.
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Required if you want to use `UJSONResponse`.
Used by FastAPI / Starlette:
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Required if you want to use `ORJSONResponse`.
You can install all of these with `pip install fastapi[all]`.
## License
This project is licensed under the terms of the MIT license.

62
docs/pt/mkdocs.yml Normal file
View File

@@ -0,0 +1,62 @@
site_name: FastAPI
site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
site_url: https://fastapi.tiangolo.com/pt/
theme:
name: material
palette:
primary: teal
accent: amber
logo: https://fastapi.tiangolo.com/img/icon-white.svg
favicon: https://fastapi.tiangolo.com/img/favicon.png
language: pt
repo_name: tiangolo/fastapi
repo_url: https://github.com/tiangolo/fastapi
edit_uri: ''
google_analytics:
- UA-133183413-1
- auto
nav:
- FastAPI: index.md
- Languages:
- en: /
- es: /es/
- pt: /pt/
- zh: /zh/
markdown_extensions:
- toc:
permalink: true
- markdown.extensions.codehilite:
guess_lang: false
- markdown_include.include:
base_path: docs
- admonition
- codehilite
- extra
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_div_format ''
extra:
social:
- type: github
link: https://github.com/tiangolo/typer
- type: twitter
link: https://twitter.com/tiangolo
- type: linkedin
link: https://www.linkedin.com/in/tiangolo
- type: rss
link: https://dev.to/tiangolo
- type: medium
link: https://medium.com/@tiangolo
- type: globe
link: https://tiangolo.com
extra_css:
- https://fastapi.tiangolo.com/css/termynal.css
- https://fastapi.tiangolo.com/css/custom.css
extra_javascript:
- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js
- https://fastapi.tiangolo.com/js/termynal.js
- https://fastapi.tiangolo.com/js/custom.js
- https://fastapi.tiangolo.com/js/chat.js
- https://sidecar.gitter.im/dist/sidecar.v1.js

View File

@@ -20,6 +20,7 @@ nav:
- Languages:
- en: /
- es: /es/
- pt: /pt/
- zh: /zh/
markdown_extensions:
- toc:

View File

@@ -0,0 +1,10 @@
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str = "Awesome API"
admin_email: str
items_per_user: int = 50
settings = Settings()

View File

@@ -0,0 +1,14 @@
from fastapi import FastAPI
from . import config
app = FastAPI()
@app.get("/info")
async def info():
return {
"app_name": config.settings.app_name,
"admin_email": config.settings.admin_email,
"items_per_user": config.settings.items_per_user,
}

View File

View File

@@ -0,0 +1,7 @@
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str = "Awesome API"
admin_email: str
items_per_user: int = 50

View File

@@ -0,0 +1,21 @@
from functools import lru_cache
from fastapi import Depends, FastAPI
from . import config
app = FastAPI()
@lru_cache()
def get_settings():
return config.Settings()
@app.get("/info")
async def info(settings: config.Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"admin_email": settings.admin_email,
"items_per_user": settings.items_per_user,
}

View File

@@ -0,0 +1,23 @@
from fastapi.testclient import TestClient
from . import config, main
client = TestClient(main.app)
def get_settings_override():
return config.Settings(admin_email="testing_admin@example.com")
main.app.dependency_overrides[main.get_settings] = get_settings_override
def test_app():
response = client.get("/info")
data = response.json()
assert data == {
"app_name": "Awesome API",
"admin_email": "testing_admin@example.com",
"items_per_user": 50,
}

View File

View File

@@ -0,0 +1,10 @@
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str = "Awesome API"
admin_email: str
items_per_user: int = 50
class Config:
env_file = ".env"

View File

@@ -0,0 +1,21 @@
from functools import lru_cache
from fastapi import Depends, FastAPI
from . import config
app = FastAPI()
@lru_cache()
def get_settings():
return config.Settings()
@app.get("/info")
async def info(settings: config.Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"admin_email": settings.admin_email,
"items_per_user": settings.items_per_user,
}

View File

@@ -0,0 +1,21 @@
from fastapi import FastAPI
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str = "Awesome API"
admin_email: str
items_per_user: int = 50
settings = Settings()
app = FastAPI()
@app.get("/info")
async def info():
return {
"app_name": settings.app_name,
"admin_email": settings.admin_email,
"items_per_user": settings.items_per_user,
}

View File

@@ -2,7 +2,7 @@ from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"
engine = create_engine(

View File

View File

@@ -0,0 +1,47 @@
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from ..database import Base
from ..main import app, get_db
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base.metadata.create_all(bind=engine)
def override_get_db():
try:
db = TestingSessionLocal()
yield db
finally:
db.close()
app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)
def test_create_user():
response = client.post(
"/users/",
json={"email": "deadpool@example.com", "password": "chimichangas4life"},
)
assert response.status_code == 200
data = response.json()
assert data["email"] == "deadpool@example.com"
assert "id" in data
user_id = data["id"]
response = client.get(f"/users/{user_id}")
assert response.status_code == 200
data = response.json()
assert data["email"] == "deadpool@example.com"
assert data["id"] == user_id

View File

@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.53.2"
__version__ = "0.54.0"
from starlette import status

View File

@@ -171,6 +171,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -197,6 +199,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -222,6 +226,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -250,6 +256,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -309,6 +317,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -334,6 +344,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -359,6 +371,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -384,6 +398,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -409,6 +425,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -434,6 +452,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -459,6 +479,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -484,6 +506,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -509,6 +533,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -534,6 +560,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -559,6 +587,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -584,6 +614,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -609,6 +641,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -634,6 +668,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -659,6 +695,8 @@ class FastAPI(Starlette):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -684,6 +722,8 @@ class FastAPI(Starlette):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,

View File

@@ -34,7 +34,8 @@ def jsonable_encoder(
by_alias: bool = True,
skip_defaults: bool = None,
exclude_unset: bool = False,
include_none: bool = True,
exclude_defaults: bool = False,
exclude_none: bool = False,
custom_encoder: dict = {},
sqlalchemy_safe: bool = True,
) -> Any:
@@ -58,8 +59,12 @@ def jsonable_encoder(
exclude=exclude,
by_alias=by_alias,
exclude_unset=bool(exclude_unset or skip_defaults),
exclude_none=exclude_none,
exclude_defaults=exclude_defaults,
)
else: # pragma: nocover
if exclude_defaults:
raise ValueError("Cannot use exclude_defaults")
obj_dict = obj.dict(
include=include,
exclude=exclude,
@@ -68,7 +73,8 @@ def jsonable_encoder(
)
return jsonable_encoder(
obj_dict,
include_none=include_none,
exclude_none=exclude_none,
exclude_defaults=exclude_defaults,
custom_encoder=encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
@@ -87,14 +93,14 @@ def jsonable_encoder(
or (not isinstance(key, str))
or (not key.startswith("_sa"))
)
and (value is not None or include_none)
and (value is not None or not exclude_none)
and ((include and key in include) or key not in exclude)
):
encoded_key = jsonable_encoder(
key,
by_alias=by_alias,
exclude_unset=exclude_unset,
include_none=include_none,
exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
@@ -102,7 +108,7 @@ def jsonable_encoder(
value,
by_alias=by_alias,
exclude_unset=exclude_unset,
include_none=include_none,
exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
@@ -118,7 +124,8 @@ def jsonable_encoder(
exclude=exclude,
by_alias=by_alias,
exclude_unset=exclude_unset,
include_none=include_none,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
@@ -153,7 +160,8 @@ def jsonable_encoder(
data,
by_alias=by_alias,
exclude_unset=exclude_unset,
include_none=include_none,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)

View File

@@ -81,7 +81,7 @@ def get_openapi_security_definitions(flat_dependant: Dependant) -> Tuple[Dict, L
security_definition = jsonable_encoder(
security_requirement.security_scheme.model,
by_alias=True,
include_none=False,
exclude_none=True,
)
security_name = security_requirement.security_scheme.scheme_name
security_definitions[security_name] = security_definition
@@ -310,4 +310,4 @@ def get_openapi(
if components:
output["components"] = components
output["paths"] = paths
return jsonable_encoder(OpenAPI(**output), by_alias=True, include_none=False)
return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True)

View File

@@ -49,22 +49,43 @@ except ImportError: # pragma: nocover
def _prepare_response_content(
res: Any, *, by_alias: bool = True, exclude_unset: bool
res: Any,
*,
by_alias: bool = True,
exclude_unset: bool,
exclude_defaults: bool = False,
exclude_none: bool = False,
) -> Any:
if isinstance(res, BaseModel):
if PYDANTIC_1:
return res.dict(by_alias=by_alias, exclude_unset=exclude_unset)
return res.dict(
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
)
else:
return res.dict(
by_alias=by_alias, skip_defaults=exclude_unset
by_alias=by_alias, skip_defaults=exclude_unset,
) # pragma: nocover
elif isinstance(res, list):
return [
_prepare_response_content(item, exclude_unset=exclude_unset) for item in res
_prepare_response_content(
item,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
)
for item in res
]
elif isinstance(res, dict):
return {
k: _prepare_response_content(v, exclude_unset=exclude_unset)
k: _prepare_response_content(
v,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
)
for k, v in res.items()
}
return res
@@ -78,12 +99,18 @@ async def serialize_response(
exclude: Union[SetIntStr, DictIntStrAny] = set(),
by_alias: bool = True,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
is_coroutine: bool = True,
) -> Any:
if field:
errors = []
response_content = _prepare_response_content(
response_content, by_alias=by_alias, exclude_unset=exclude_unset
response_content,
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
)
if is_coroutine:
value, errors_ = field.validate(response_content, {}, loc=("response",))
@@ -103,6 +130,8 @@ async def serialize_response(
exclude=exclude,
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
)
else:
return jsonable_encoder(response_content)
@@ -131,6 +160,8 @@ def get_request_handler(
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(),
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
dependency_overrides_provider: Any = None,
) -> Callable:
assert dependant.call is not None, "dependant.call must be a function"
@@ -177,6 +208,8 @@ def get_request_handler(
exclude=response_model_exclude,
by_alias=response_model_by_alias,
exclude_unset=response_model_exclude_unset,
exclude_defaults=response_model_exclude_defaults,
exclude_none=response_model_exclude_none,
is_coroutine=is_coroutine,
)
response = response_class(
@@ -255,6 +288,8 @@ class APIRoute(routing.Route):
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(),
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Optional[Type[Response]] = None,
dependency_overrides_provider: Any = None,
@@ -326,6 +361,8 @@ class APIRoute(routing.Route):
self.response_model_exclude = response_model_exclude
self.response_model_by_alias = response_model_by_alias
self.response_model_exclude_unset = response_model_exclude_unset
self.response_model_exclude_defaults = response_model_exclude_defaults
self.response_model_exclude_none = response_model_exclude_none
self.include_in_schema = include_in_schema
self.response_class = response_class
@@ -352,6 +389,8 @@ class APIRoute(routing.Route):
response_model_exclude=self.response_model_exclude,
response_model_by_alias=self.response_model_by_alias,
response_model_exclude_unset=self.response_model_exclude_unset,
response_model_exclude_defaults=self.response_model_exclude_defaults,
response_model_exclude_none=self.response_model_exclude_none,
dependency_overrides_provider=self.dependency_overrides_provider,
)
@@ -400,6 +439,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -429,6 +470,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -457,6 +500,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -486,6 +531,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -560,6 +607,8 @@ class APIRouter(routing.Router):
response_model_exclude=route.response_model_exclude,
response_model_by_alias=route.response_model_by_alias,
response_model_exclude_unset=route.response_model_exclude_unset,
response_model_exclude_defaults=route.response_model_exclude_defaults,
response_model_exclude_none=route.response_model_exclude_none,
include_in_schema=route.include_in_schema,
response_class=route.response_class or default_response_class,
name=route.name,
@@ -606,6 +655,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -632,6 +683,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -657,6 +710,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -683,6 +738,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -708,6 +765,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -734,6 +793,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -759,6 +820,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -785,6 +848,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -810,6 +875,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -836,6 +903,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -861,6 +930,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -887,6 +958,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -912,6 +985,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -938,6 +1013,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
@@ -963,6 +1040,8 @@ class APIRouter(routing.Router):
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
@@ -989,6 +1068,8 @@ class APIRouter(routing.Router):
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,

View File

@@ -3,10 +3,6 @@
set -e
set -x
# Remove temporary DB
if [ -f ./test.db ]; then
rm ./test.db
fi
bash ./scripts/lint.sh
# Check README.md is up to date
diff --brief docs/en/docs/index.md README.md

View File

@@ -70,6 +70,12 @@ class ModelWithAlias(BaseModel):
foo: str = Field(..., alias="Foo")
class ModelWithDefault(BaseModel):
foo: str = ...
bar: str = "bar"
bla: str = "bla"
@pytest.fixture(
name="model_with_path", params=[PurePath, PurePosixPath, PureWindowsPath]
)
@@ -121,6 +127,16 @@ def test_encode_model_with_alias():
assert jsonable_encoder(model) == {"Foo": "Bar"}
def test_encode_model_with_default():
model = ModelWithDefault(foo="foo", bar="bar")
assert jsonable_encoder(model) == {"foo": "foo", "bar": "bar", "bla": "bla"}
assert jsonable_encoder(model, exclude_unset=True) == {"foo": "foo", "bar": "bar"}
assert jsonable_encoder(model, exclude_defaults=True) == {"foo": "foo"}
assert jsonable_encoder(model, exclude_unset=True, exclude_defaults=True) == {
"foo": "foo"
}
def test_custom_encoders():
class safe_datetime(datetime):
pass

View File

@@ -18,11 +18,53 @@ class Model(BaseModel):
class ModelSubclass(Model):
y: int
z: int = 0
w: int = None
class ModelDefaults(BaseModel):
w: Optional[str] = None
x: Optional[str] = None
y: str = "y"
z: str = "z"
@app.get("/", response_model=Model, response_model_exclude_unset=True)
def get() -> ModelSubclass:
return ModelSubclass(sub={}, y=1)
return ModelSubclass(sub={}, y=1, z=0)
@app.get(
"/exclude_unset", response_model=ModelDefaults, response_model_exclude_unset=True
)
def get() -> ModelDefaults:
return ModelDefaults(x=None, y="y")
@app.get(
"/exclude_defaults",
response_model=ModelDefaults,
response_model_exclude_defaults=True,
)
def get() -> ModelDefaults:
return ModelDefaults(x=None, y="y")
@app.get(
"/exclude_none", response_model=ModelDefaults, response_model_exclude_none=True
)
def get() -> ModelDefaults:
return ModelDefaults(x=None, y="y")
@app.get(
"/exclude_unset_none",
response_model=ModelDefaults,
response_model_exclude_unset=True,
response_model_exclude_none=True,
)
def get() -> ModelDefaults:
return ModelDefaults(x=None, y="y")
client = TestClient(app)
@@ -31,3 +73,23 @@ client = TestClient(app)
def test_return_defaults():
response = client.get("/")
assert response.json() == {"sub": {}}
def test_return_exclude_unset():
response = client.get("/exclude_unset")
assert response.json() == {"x": None, "y": "y"}
def test_return_exclude_defaults():
response = client.get("/exclude_defaults")
assert response.json() == {}
def test_return_exclude_none():
response = client.get("/exclude_none")
assert response.json() == {"y": "y", "z": "z"}
def test_return_exclude_unset_none():
response = client.get("/exclude_unset_none")
assert response.json() == {"y": "y"}

View File

View File

@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from application_configuration.tutorial001 import app
from metadata.tutorial001 import app
client = TestClient(app)

View File

View File

@@ -0,0 +1,9 @@
from fastapi.testclient import TestClient
from settings.app02 import main, test_main
client = TestClient(main.app)
def test_setting_override():
test_main.test_app()

View File

@@ -286,7 +286,7 @@ def client():
# Import while creating the client to create the DB after starting the test session
from sql_databases.sql_app.main import app
test_db = Path("./test.db")
test_db = Path("./sql_app.db")
with TestClient(app) as c:
yield c
test_db.unlink()

View File

@@ -286,7 +286,7 @@ def client():
# Import while creating the client to create the DB after starting the test session
from sql_databases.sql_app.alt_main import app
test_db = Path("./test.db")
test_db = Path("./sql_app.db")
with TestClient(app) as c:
yield c
test_db.unlink()

View File

@@ -0,0 +1,13 @@
from pathlib import Path
def test_testing_dbs():
# Import while creating the client to create the DB after starting the test session
from sql_databases.sql_app.tests.test_sql_app import test_create_user
test_db = Path("./test.db")
app_db = Path("./sql_app.db")
test_create_user()
test_db.unlink()
if app_db.is_file(): # pragma: nocover
app_db.unlink()