mirror of
https://github.com/fastapi/fastapi.git
synced 2026-02-13 15:51:14 -05:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5420847d9f | ||
|
|
5ad9d258e4 | ||
|
|
d213dd363d | ||
|
|
0d1f4d935b | ||
|
|
9d42132e7a | ||
|
|
dd50de1205 | ||
|
|
7dbdb11fb0 | ||
|
|
eada361fa2 | ||
|
|
149ef6264e | ||
|
|
54e29fbad8 | ||
|
|
685cc0de17 | ||
|
|
ea8db708f1 | ||
|
|
fdbbf74908 | ||
|
|
b93c964d7f | ||
|
|
7c4b134464 | ||
|
|
db328270aa | ||
|
|
6fa573ce0b | ||
|
|
55a9eee13a | ||
|
|
c206f19b5d | ||
|
|
d11f820ac3 |
@@ -7,6 +7,25 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update docs for JWT to prevent timing attacks. PR [#14908](https://github.com/fastapi/fastapi/pull/14908) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Update translations for ja (update-all). PR [#14916](https://github.com/fastapi/fastapi/pull/14916) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for pt (update-all). PR [#14912](https://github.com/fastapi/fastapi/pull/14912) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for es (update-all and add-missing). PR [#14911](https://github.com/fastapi/fastapi/pull/14911) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for zh (update-all). PR [#14917](https://github.com/fastapi/fastapi/pull/14917) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for uk (update-all). PR [#14914](https://github.com/fastapi/fastapi/pull/14914) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for tr (update-all). PR [#14913](https://github.com/fastapi/fastapi/pull/14913) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for ru (update-outdated). PR [#14909](https://github.com/fastapi/fastapi/pull/14909) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
|
||||
### Internal
|
||||
|
||||
* ⬆ Bump cryptography from 46.0.4 to 46.0.5. PR [#14892](https://github.com/fastapi/fastapi/pull/14892) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump pillow from 12.1.0 to 12.1.1. PR [#14899](https://github.com/fastapi/fastapi/pull/14899) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
|
||||
## 0.129.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -116,7 +116,11 @@ And another utility to verify if a received password matches the hash stored.
|
||||
|
||||
And another one to authenticate and return a user.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
|
||||
|
||||
When `authenticate_user` is called with a username that doesn't exist in the database, we still run `verify_password` against a dummy hash.
|
||||
|
||||
This ensures the endpoint takes roughly the same amount of time to respond whether the username is valid or not, preventing **timing attacks** that could be used to enumerate existing usernames.
|
||||
|
||||
/// note
|
||||
|
||||
@@ -152,7 +156,7 @@ Define a Pydantic Model that will be used in the token endpoint for the response
|
||||
|
||||
Create a utility function to generate a new access token.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
|
||||
|
||||
## Update the dependencies { #update-the-dependencies }
|
||||
|
||||
@@ -162,7 +166,7 @@ Decode the received token, verify it, and return the current user.
|
||||
|
||||
If the token is invalid, return an HTTP error right away.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
|
||||
|
||||
## Update the `/token` *path operation* { #update-the-token-path-operation }
|
||||
|
||||
@@ -170,7 +174,7 @@ Create a `timedelta` with the expiration time of the token.
|
||||
|
||||
Create a real JWT access token and return it.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
|
||||
|
||||
### Technical details about the JWT "subject" `sub` { #technical-details-about-the-jwt-subject-sub }
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Cada uno de esos `dict`s de response puede tener una clave `model`, conteniendo
|
||||
|
||||
Por ejemplo, para declarar otro response con un código de estado `404` y un modelo Pydantic `Message`, puedes escribir:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
|
||||
{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
@@ -203,7 +203,7 @@ Por ejemplo, puedes declarar un response con un código de estado `404` que usa
|
||||
|
||||
Y un response con un código de estado `200` que usa tu `response_model`, pero incluye un `example` personalizado:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
|
||||
{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
|
||||
|
||||
Todo se combinará e incluirá en tu OpenAPI, y se mostrará en la documentación de la API:
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ No la clase en sí (que ya es un callable), sino una instance de esa clase.
|
||||
|
||||
Para hacer eso, declaramos un método `__call__`:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
|
||||
|
||||
En este caso, este `__call__` es lo que **FastAPI** usará para comprobar parámetros adicionales y sub-dependencias, y es lo que llamará para pasar un valor al parámetro en tu *path operation function* más adelante.
|
||||
|
||||
@@ -26,7 +26,7 @@ En este caso, este `__call__` es lo que **FastAPI** usará para comprobar parám
|
||||
|
||||
Y ahora, podemos usar `__init__` para declarar los parámetros de la instance que podemos usar para "parametrizar" la dependencia:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
|
||||
|
||||
En este caso, **FastAPI** nunca tocará ni se preocupará por `__init__`, lo usaremos directamente en nuestro código.
|
||||
|
||||
@@ -34,7 +34,7 @@ En este caso, **FastAPI** nunca tocará ni se preocupará por `__init__`, lo usa
|
||||
|
||||
Podríamos crear una instance de esta clase con:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
|
||||
|
||||
Y de esa manera podemos "parametrizar" nuestra dependencia, que ahora tiene `"bar"` dentro de ella, como el atributo `checker.fixed_content`.
|
||||
|
||||
@@ -50,7 +50,7 @@ checker(q="somequery")
|
||||
|
||||
...y pasará lo que eso retorne como el valor de la dependencia en nuestra *path operation function* como el parámetro `fixed_content_included`:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
61
docs/es/docs/advanced/advanced-python-types.md
Normal file
61
docs/es/docs/advanced/advanced-python-types.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Tipos avanzados de Python { #advanced-python-types }
|
||||
|
||||
Aquí tienes algunas ideas adicionales que podrían ser útiles al trabajar con tipos de Python.
|
||||
|
||||
## Usar `Union` u `Optional` { #using-union-or-optional }
|
||||
|
||||
Si por alguna razón tu código no puede usar `|`, por ejemplo si no está en una anotación de tipos sino en algo como `response_model=`, en lugar de usar la barra vertical (`|`) puedes usar `Union` de `typing`.
|
||||
|
||||
Por ejemplo, podrías declarar que algo podría ser un `str` o `None`:
|
||||
|
||||
```python
|
||||
from typing import Union
|
||||
|
||||
|
||||
def say_hi(name: Union[str, None]):
|
||||
print(f"Hi {name}!")
|
||||
```
|
||||
|
||||
`typing` también tiene un atajo para declarar que algo podría ser `None`, con `Optional`.
|
||||
|
||||
Aquí va un Consejo desde mi punto de vista muy subjetivo:
|
||||
|
||||
* 🚨 Evita usar `Optional[SomeType]`
|
||||
* En su lugar ✨ **usa `Union[SomeType, None]`** ✨.
|
||||
|
||||
Ambas son equivalentes y por debajo son lo mismo, pero recomendaría `Union` en lugar de `Optional` porque la palabra "**optional**" parecería implicar que el valor es opcional, y en realidad significa "puede ser `None`", incluso si no es opcional y sigue siendo requerido.
|
||||
|
||||
Creo que `Union[SomeType, None]` es más explícito respecto a lo que significa.
|
||||
|
||||
Se trata solo de palabras y nombres. Pero esas palabras pueden afectar cómo tú y tu equipo piensan sobre el código.
|
||||
|
||||
Como ejemplo, tomemos esta función:
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def say_hi(name: Optional[str]):
|
||||
print(f"Hey {name}!")
|
||||
```
|
||||
|
||||
El parámetro `name` está definido como `Optional[str]`, pero **no es opcional**, no puedes llamar a la función sin el parámetro:
|
||||
|
||||
```Python
|
||||
say_hi() # ¡Oh, no, esto lanza un error! 😱
|
||||
```
|
||||
|
||||
El parámetro `name` **sigue siendo requerido** (no es *opcional*) porque no tiene un valor por defecto. Aun así, `name` acepta `None` como valor:
|
||||
|
||||
```Python
|
||||
say_hi(name=None) # Esto funciona, None es válido 🎉
|
||||
```
|
||||
|
||||
La buena noticia es que, en la mayoría de los casos, podrás simplemente usar `|` para definir uniones de tipos:
|
||||
|
||||
```python
|
||||
def say_hi(name: str | None):
|
||||
print(f"Hey {name}!")
|
||||
```
|
||||
|
||||
Así que, normalmente no tienes que preocuparte por nombres como `Optional` y `Union`. 😎
|
||||
@@ -32,11 +32,11 @@ Para un ejemplo simple, consideremos una estructura de archivos similar a la des
|
||||
|
||||
El archivo `main.py` tendría:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py39/main.py *}
|
||||
{* ../../docs_src/async_tests/app_a_py310/main.py *}
|
||||
|
||||
El archivo `test_main.py` tendría los tests para `main.py`, podría verse así ahora:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py39/test_main.py *}
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
|
||||
|
||||
## Ejecútalo { #run-it }
|
||||
|
||||
@@ -56,7 +56,7 @@ $ pytest
|
||||
|
||||
El marcador `@pytest.mark.anyio` le dice a pytest que esta función de test debe ser llamada asíncronamente:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -66,7 +66,7 @@ Nota que la función de test ahora es `async def` en lugar de solo `def` como an
|
||||
|
||||
Luego podemos crear un `AsyncClient` con la app y enviar requests asíncronos a ella, usando `await`.
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
|
||||
|
||||
Esto es equivalente a:
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*"
|
||||
|
||||
Por ejemplo, digamos que defines una *path operation* `/items/`:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *}
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
|
||||
|
||||
Si el cliente intenta ir a `/items`, por defecto, sería redirigido a `/items/`.
|
||||
|
||||
@@ -115,7 +115,7 @@ En este caso, el path original `/app` realmente sería servido en `/api/v1/app`.
|
||||
|
||||
Aunque todo tu código esté escrito asumiendo que solo existe `/app`.
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *}
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
|
||||
|
||||
Y el proxy estaría **"eliminando"** el **prefijo del path** sobre la marcha antes de transmitir el request al servidor de aplicaciones (probablemente Uvicorn a través de FastAPI CLI), manteniendo a tu aplicación convencida de que está siendo servida en `/app`, así que no tienes que actualizar todo tu código para incluir el prefijo `/api/v1`.
|
||||
|
||||
@@ -193,7 +193,7 @@ Puedes obtener el `root_path` actual utilizado por tu aplicación para cada requ
|
||||
|
||||
Aquí lo estamos incluyendo en el mensaje solo con fines de demostración.
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *}
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
|
||||
|
||||
Luego, si inicias Uvicorn con:
|
||||
|
||||
@@ -220,7 +220,7 @@ El response sería algo como:
|
||||
|
||||
Alternativamente, si no tienes una forma de proporcionar una opción de línea de comandos como `--root-path` o su equivalente, puedes configurar el parámetro `root_path` al crear tu app de FastAPI:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *}
|
||||
{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
|
||||
|
||||
Pasar el `root_path` a `FastAPI` sería el equivalente a pasar la opción de línea de comandos `--root-path` a Uvicorn o Hypercorn.
|
||||
|
||||
@@ -400,7 +400,7 @@ Si pasas una lista personalizada de `servers` y hay un `root_path` (porque tu AP
|
||||
|
||||
Por ejemplo:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *}
|
||||
{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
|
||||
|
||||
Generará un esquema de OpenAPI como:
|
||||
|
||||
@@ -455,7 +455,7 @@ Si no especificas el parámetro `servers` y `root_path` es igual a `/`, la propi
|
||||
|
||||
Si no quieres que **FastAPI** incluya un server automático usando el `root_path`, puedes usar el parámetro `root_path_in_servers=False`:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *}
|
||||
{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
|
||||
|
||||
y entonces no lo incluirá en el esquema de OpenAPI.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Esto se debe a que, por defecto, FastAPI inspeccionará cada elemento dentro y s
|
||||
|
||||
Pero si estás seguro de que el contenido que estás devolviendo es **serializable con JSON**, puedes pasarlo directamente a la clase de response y evitar la sobrecarga extra que FastAPI tendría al pasar tu contenido de retorno a través de `jsonable_encoder` antes de pasarlo a la clase de response.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
|
||||
|
||||
/// info | Información
|
||||
|
||||
@@ -55,7 +55,7 @@ Para devolver un response con HTML directamente desde **FastAPI**, usa `HTMLResp
|
||||
* Importa `HTMLResponse`.
|
||||
* Pasa `HTMLResponse` como parámetro `response_class` de tu *path operation decorator*.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
|
||||
|
||||
/// info | Información
|
||||
|
||||
@@ -73,7 +73,7 @@ Como se ve en [Devolver una Response directamente](response-directly.md){.intern
|
||||
|
||||
El mismo ejemplo de arriba, devolviendo una `HTMLResponse`, podría verse así:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
|
||||
{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
|
||||
|
||||
/// warning | Advertencia
|
||||
|
||||
@@ -97,7 +97,7 @@ El `response_class` solo se usará para documentar el OpenAPI *path operation*,
|
||||
|
||||
Por ejemplo, podría ser algo así:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
|
||||
{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
|
||||
|
||||
En este ejemplo, la función `generate_html_response()` ya genera y devuelve una `Response` en lugar de devolver el HTML en un `str`.
|
||||
|
||||
@@ -136,7 +136,7 @@ Acepta los siguientes parámetros:
|
||||
|
||||
FastAPI (de hecho Starlette) incluirá automáticamente un header Content-Length. También incluirá un header Content-Type, basado en el `media_type` y añadiendo un conjunto de caracteres para tipos de texto.
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
|
||||
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
|
||||
|
||||
### `HTMLResponse` { #htmlresponse }
|
||||
|
||||
@@ -146,7 +146,7 @@ Toma algún texto o bytes y devuelve un response HTML, como leíste arriba.
|
||||
|
||||
Toma algún texto o bytes y devuelve un response de texto plano.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
|
||||
|
||||
### `JSONResponse` { #jsonresponse }
|
||||
|
||||
@@ -180,7 +180,7 @@ Esto requiere instalar `ujson`, por ejemplo, con `pip install ujson`.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -194,15 +194,15 @@ Devuelve una redirección HTTP. Usa un código de estado 307 (Redirección Tempo
|
||||
|
||||
Puedes devolver un `RedirectResponse` directamente:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
|
||||
|
||||
---
|
||||
|
||||
O puedes usarlo en el parámetro `response_class`:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
|
||||
|
||||
Si haces eso, entonces puedes devolver la URL directamente desde tu *path operation function*.
|
||||
Si haces eso, entonces puedes devolver la URL directamente desde tu *path operation* function.
|
||||
|
||||
En este caso, el `status_code` utilizado será el por defecto para `RedirectResponse`, que es `307`.
|
||||
|
||||
@@ -210,13 +210,13 @@ En este caso, el `status_code` utilizado será el por defecto para `RedirectResp
|
||||
|
||||
También puedes usar el parámetro `status_code` combinado con el parámetro `response_class`:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
|
||||
|
||||
### `StreamingResponse` { #streamingresponse }
|
||||
|
||||
Toma un generador `async` o un generador/iterador normal y transmite el cuerpo del response.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
|
||||
{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
|
||||
|
||||
#### Usando `StreamingResponse` con objetos similares a archivos { #using-streamingresponse-with-file-like-objects }
|
||||
|
||||
@@ -226,7 +226,7 @@ De esa manera, no tienes que leerlo todo primero en memoria, y puedes pasar esa
|
||||
|
||||
Esto incluye muchos paquetes para interactuar con almacenamiento en la nube, procesamiento de video y otros.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
|
||||
{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
|
||||
|
||||
1. Esta es la función generadora. Es una "función generadora" porque contiene declaraciones `yield` dentro.
|
||||
2. Al usar un bloque `with`, nos aseguramos de que el objeto similar a un archivo se cierre después de que la función generadora termine. Así, después de que termina de enviar el response.
|
||||
@@ -255,11 +255,11 @@ Toma un conjunto diferente de argumentos para crear un instance que los otros ti
|
||||
|
||||
Los responses de archivos incluirán los headers apropiados `Content-Length`, `Last-Modified` y `ETag`.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
|
||||
{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
|
||||
|
||||
También puedes usar el parámetro `response_class`:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
|
||||
{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
|
||||
|
||||
En este caso, puedes devolver la path del archivo directamente desde tu *path operation* function.
|
||||
|
||||
@@ -273,7 +273,7 @@ Digamos que quieres que devuelva JSON con sangría y formato, por lo que quieres
|
||||
|
||||
Podrías crear un `CustomORJSONResponse`. Lo principal que tienes que hacer es crear un método `Response.render(content)` que devuelva el contenido como `bytes`:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
|
||||
{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
|
||||
|
||||
Ahora en lugar de devolver:
|
||||
|
||||
@@ -299,7 +299,7 @@ El parámetro que define esto es `default_response_class`.
|
||||
|
||||
En el ejemplo a continuación, **FastAPI** usará `ORJSONResponse` por defecto, en todas las *path operations*, en lugar de `JSONResponse`.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
|
||||
{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ En ese caso, simplemente puedes intercambiar los `dataclasses` estándar con `py
|
||||
|
||||
6. Aquí estamos regresando un diccionario que contiene `items`, que es una lista de dataclasses.
|
||||
|
||||
FastAPI todavía es capaz de <abbr title="convertir los datos a un formato que pueda transmitirse">serializar</abbr> los datos a JSON.
|
||||
FastAPI todavía es capaz de <dfn title="convertir los datos a un formato que pueda transmitirse">serializar</dfn> los datos a JSON.
|
||||
|
||||
7. Aquí el `response_model` está usando una anotación de tipo de una lista de dataclasses `Author`.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Comencemos con un ejemplo y luego veámoslo en detalle.
|
||||
|
||||
Creamos una función asíncrona `lifespan()` con `yield` así:
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
|
||||
|
||||
Aquí estamos simulando la operación costosa de *startup* de cargar el modelo poniendo la función del (falso) modelo en el diccionario con modelos de machine learning antes del `yield`. Este código será ejecutado **antes** de que la aplicación **comience a tomar requests**, durante el *startup*.
|
||||
|
||||
@@ -48,7 +48,7 @@ Quizás necesites iniciar una nueva versión, o simplemente te cansaste de ejecu
|
||||
|
||||
Lo primero que hay que notar es que estamos definiendo una función asíncrona con `yield`. Esto es muy similar a las Dependencias con `yield`.
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
|
||||
|
||||
La primera parte de la función, antes del `yield`, será ejecutada **antes** de que la aplicación comience.
|
||||
|
||||
@@ -60,7 +60,7 @@ Si revisas, la función está decorada con un `@asynccontextmanager`.
|
||||
|
||||
Eso convierte a la función en algo llamado un "**async context manager**".
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
|
||||
|
||||
Un **context manager** en Python es algo que puedes usar en un statement `with`, por ejemplo, `open()` puede ser usado como un context manager:
|
||||
|
||||
@@ -82,7 +82,7 @@ En nuestro ejemplo de código arriba, no lo usamos directamente, pero se lo pasa
|
||||
|
||||
El parámetro `lifespan` de la app de `FastAPI` toma un **async context manager**, por lo que podemos pasar nuestro nuevo `lifespan` async context manager a él.
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py39.py hl[22] *}
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
|
||||
|
||||
## Eventos Alternativos (obsoleto) { #alternative-events-deprecated }
|
||||
|
||||
@@ -104,7 +104,7 @@ Estas funciones pueden ser declaradas con `async def` o `def` normal.
|
||||
|
||||
Para añadir una función que debería ejecutarse antes de que la aplicación inicie, declárala con el evento `"startup"`:
|
||||
|
||||
{* ../../docs_src/events/tutorial001_py39.py hl[8] *}
|
||||
{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
|
||||
|
||||
En este caso, la función manejadora del evento `startup` inicializará los ítems de la "base de datos" (solo un `dict`) con algunos valores.
|
||||
|
||||
@@ -116,7 +116,7 @@ Y tu aplicación no comenzará a recibir requests hasta que todos los manejadore
|
||||
|
||||
Para añadir una función que debería ejecutarse cuando la aplicación se esté cerrando, declárala con el evento `"shutdown"`:
|
||||
|
||||
{* ../../docs_src/events/tutorial002_py39.py hl[6] *}
|
||||
{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
|
||||
|
||||
Aquí, la función manejadora del evento `shutdown` escribirá una línea de texto `"Application shutdown"` a un archivo `log.txt`.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Como **FastAPI** está basado en la especificación **OpenAPI**, sus APIs se pueden describir en un formato estándar que muchas herramientas entienden.
|
||||
|
||||
Esto facilita generar **documentación** actualizada, paquetes de cliente (<abbr title="Software Development Kits – Kits de Desarrollo de Software">**SDKs**</abbr>) en múltiples lenguajes y **escribir pruebas** o **flujos de automatización** que se mantengan sincronizados con tu código.
|
||||
Esto facilita generar **documentación** actualizada, paquetes de cliente (<abbr title="Software Development Kits - Kits de Desarrollo de Software">**SDKs**</abbr>) en múltiples lenguajes y **escribir pruebas** o **flujos de automatización** que se mantengan sincronizados con tu código.
|
||||
|
||||
En esta guía, aprenderás a generar un **SDK de TypeScript** para tu backend con FastAPI.
|
||||
|
||||
@@ -40,7 +40,7 @@ Algunas de estas soluciones también pueden ser open source u ofrecer niveles gr
|
||||
|
||||
Empecemos con una aplicación simple de FastAPI:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
|
||||
{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
|
||||
|
||||
Nota que las *path operations* definen los modelos que usan para el payload del request y el payload del response, usando los modelos `Item` y `ResponseMessage`.
|
||||
|
||||
@@ -98,7 +98,7 @@ En muchos casos tu app de FastAPI será más grande, y probablemente usarás tag
|
||||
|
||||
Por ejemplo, podrías tener una sección para **items** y otra sección para **users**, y podrían estar separadas por tags:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *}
|
||||
{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
|
||||
|
||||
### Genera un Cliente TypeScript con tags { #generate-a-typescript-client-with-tags }
|
||||
|
||||
@@ -145,7 +145,7 @@ Por ejemplo, aquí está usando el primer tag (probablemente tendrás solo un ta
|
||||
|
||||
Puedes entonces pasar esa función personalizada a **FastAPI** como el parámetro `generate_unique_id_function`:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *}
|
||||
{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
|
||||
|
||||
### Genera un Cliente TypeScript con operation IDs personalizados { #generate-a-typescript-client-with-custom-operation-ids }
|
||||
|
||||
@@ -167,7 +167,7 @@ Pero para el cliente generado podríamos **modificar** los operation IDs de Open
|
||||
|
||||
Podríamos descargar el JSON de OpenAPI a un archivo `openapi.json` y luego podríamos **remover ese tag prefijado** con un script como este:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial004_py39.py *}
|
||||
{* ../../docs_src/generate_clients/tutorial004_py310.py *}
|
||||
|
||||
//// tab | Node.js
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ En esta sección veremos cómo usar otros middlewares.
|
||||
|
||||
## Agregando middlewares ASGI { #adding-asgi-middlewares }
|
||||
|
||||
Como **FastAPI** está basado en Starlette e implementa la especificación <abbr title="Asynchronous Server Gateway Interface – Interfaz de puerta de enlace de servidor asíncrona">ASGI</abbr>, puedes usar cualquier middleware ASGI.
|
||||
Como **FastAPI** está basado en Starlette e implementa la especificación <abbr title="Asynchronous Server Gateway Interface - Interfaz de puerta de enlace de servidor asíncrona">ASGI</abbr>, puedes usar cualquier middleware ASGI.
|
||||
|
||||
Un middleware no tiene que estar hecho para FastAPI o Starlette para funcionar, siempre que siga la especificación ASGI.
|
||||
|
||||
@@ -57,13 +57,13 @@ Impone que todas las requests entrantes deben ser `https` o `wss`.
|
||||
|
||||
Cualquier request entrante a `http` o `ws` será redirigida al esquema seguro.
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *}
|
||||
{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
|
||||
|
||||
## `TrustedHostMiddleware` { #trustedhostmiddleware }
|
||||
|
||||
Impone que todas las requests entrantes tengan correctamente configurado el header `Host`, para proteger contra ataques de HTTP Host Header.
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *}
|
||||
{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
|
||||
|
||||
Se soportan los siguientes argumentos:
|
||||
|
||||
@@ -78,7 +78,7 @@ Maneja responses GZip para cualquier request que incluya `"gzip"` en el header `
|
||||
|
||||
El middleware manejará tanto responses estándar como en streaming.
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *}
|
||||
{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
|
||||
|
||||
Se soportan los siguientes argumentos:
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Los webhooks están disponibles en OpenAPI 3.1.0 y superiores, soportados por Fa
|
||||
|
||||
Cuando creas una aplicación de **FastAPI**, hay un atributo `webhooks` que puedes usar para definir *webhooks*, de la misma manera que definirías *path operations*, por ejemplo con `@app.webhooks.post()`.
|
||||
|
||||
{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *}
|
||||
{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
|
||||
|
||||
Los webhooks que defines terminarán en el esquema de **OpenAPI** y en la interfaz automática de **documentación**.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Puedes establecer el `operationId` de OpenAPI para ser usado en tu *path operati
|
||||
|
||||
Tendrías que asegurarte de que sea único para cada operación.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
|
||||
|
||||
### Usar el nombre de la *path operation function* como el operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
|
||||
@@ -20,7 +20,7 @@ Si quieres usar los nombres de las funciones de tus APIs como `operationId`s, pu
|
||||
|
||||
Deberías hacerlo después de agregar todas tus *path operations*.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -40,7 +40,7 @@ Incluso si están en diferentes módulos (archivos de Python).
|
||||
|
||||
Para excluir una *path operation* del esquema OpenAPI generado (y por lo tanto, de los sistemas de documentación automática), utiliza el parámetro `include_in_schema` y configúralo en `False`:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
|
||||
|
||||
## Descripción avanzada desde el docstring { #advanced-description-from-docstring }
|
||||
|
||||
@@ -92,7 +92,7 @@ Puedes extender el esquema de OpenAPI para una *path operation* usando el parám
|
||||
|
||||
Este `openapi_extra` puede ser útil, por ejemplo, para declarar [Extensiones de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
|
||||
|
||||
Si abres la documentación automática de la API, tu extensión aparecerá en la parte inferior de la *path operation* específica.
|
||||
|
||||
@@ -139,9 +139,9 @@ Por ejemplo, podrías decidir leer y validar el request con tu propio código, s
|
||||
|
||||
Podrías hacer eso con `openapi_extra`:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
|
||||
|
||||
En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el request body ni siquiera se <abbr title="converted from some plain format, like bytes, into Python objects - convertido de algún formato plano, como bytes, a objetos de Python">parse</abbr> como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de parsearlo de alguna manera.
|
||||
En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el request body ni siquiera es <dfn title="convertido desde algún formato plano, como bytes, a objetos de Python">parseado</dfn> como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de parsearlo de alguna manera.
|
||||
|
||||
Sin embargo, podemos declarar el esquema esperado para el request body.
|
||||
|
||||
@@ -153,7 +153,7 @@ Y podrías hacer esto incluso si el tipo de datos en el request no es JSON.
|
||||
|
||||
Por ejemplo, en esta aplicación no usamos la funcionalidad integrada de FastAPI para extraer el JSON Schema de los modelos Pydantic ni la validación automática para JSON. De hecho, estamos declarando el tipo de contenido del request como YAML, no JSON:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
|
||||
|
||||
Sin embargo, aunque no estamos usando la funcionalidad integrada por defecto, aún estamos usando un modelo Pydantic para generar manualmente el JSON Schema para los datos que queremos recibir en YAML.
|
||||
|
||||
@@ -161,7 +161,7 @@ Luego usamos el request directamente, y extraemos el cuerpo como `bytes`. Esto s
|
||||
|
||||
Y luego en nuestro código, parseamos ese contenido YAML directamente, y nuevamente estamos usando el mismo modelo Pydantic para validar el contenido YAML:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ Puedes declarar un parámetro de tipo `Response` en tu *path operation function*
|
||||
|
||||
Y luego puedes establecer el `status_code` en ese objeto de response *temporal*.
|
||||
|
||||
{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *}
|
||||
{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
|
||||
|
||||
Y luego puedes devolver cualquier objeto que necesites, como lo harías normalmente (un `dict`, un modelo de base de datos, etc.).
|
||||
Y luego puedes devolver cualquier objeto que necesites, como lo harías normalmente (un `dict`, un modelo de base de datos, etc).
|
||||
|
||||
Y si declaraste un `response_model`, todavía se utilizará para filtrar y convertir el objeto que devolviste.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Puedes declarar un parámetro de tipo `Response` en tu *path operation function*
|
||||
|
||||
Y luego puedes establecer cookies en ese objeto de response *temporal*.
|
||||
|
||||
{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *}
|
||||
{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
|
||||
|
||||
Y entonces puedes devolver cualquier objeto que necesites, como normalmente lo harías (un `dict`, un modelo de base de datos, etc).
|
||||
|
||||
@@ -24,7 +24,7 @@ Para hacer eso, puedes crear un response como se describe en [Devolver un Respon
|
||||
|
||||
Luego establece Cookies en ella, y luego devuélvela:
|
||||
|
||||
{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *}
|
||||
{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ Digamos que quieres devolver un response en <a href="https://en.wikipedia.org/wi
|
||||
|
||||
Podrías poner tu contenido XML en un string, poner eso en un `Response`, y devolverlo:
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
|
||||
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
|
||||
|
||||
## Notas { #notes }
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Puedes declarar un parámetro de tipo `Response` en tu *path operation function*
|
||||
|
||||
Y luego puedes establecer headers en ese objeto de response *temporal*.
|
||||
|
||||
{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *}
|
||||
{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}
|
||||
|
||||
Y luego puedes devolver cualquier objeto que necesites, como harías normalmente (un `dict`, un modelo de base de datos, etc).
|
||||
|
||||
@@ -22,7 +22,7 @@ También puedes agregar headers cuando devuelves un `Response` directamente.
|
||||
|
||||
Crea un response como se describe en [Retorna un Response Directamente](response-directly.md){.internal-link target=_blank} y pasa los headers como un parámetro adicional:
|
||||
|
||||
{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *}
|
||||
{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
|
||||
|
||||
/// note | Detalles Técnicos
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Luego, cuando escribes ese nombre de usuario y contraseña, el navegador los env
|
||||
* Devuelve un objeto de tipo `HTTPBasicCredentials`:
|
||||
* Contiene el `username` y `password` enviados.
|
||||
|
||||
{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
|
||||
{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
|
||||
|
||||
Cuando intentas abrir la URL por primera vez (o haces clic en el botón "Execute" en la documentación) el navegador te pedirá tu nombre de usuario y contraseña:
|
||||
|
||||
@@ -40,7 +40,7 @@ Para manejar eso, primero convertimos el `username` y `password` a `bytes` codif
|
||||
|
||||
Luego podemos usar `secrets.compare_digest()` para asegurar que `credentials.username` es `"stanleyjobson"`, y que `credentials.password` es `"swordfish"`.
|
||||
|
||||
{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
|
||||
{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
|
||||
|
||||
Esto sería similar a:
|
||||
|
||||
@@ -104,4 +104,4 @@ De esa manera, usando `secrets.compare_digest()` en el código de tu aplicación
|
||||
|
||||
Después de detectar que las credenciales son incorrectas, regresa un `HTTPException` con un código de estado 401 (el mismo que se devuelve cuando no se proporcionan credenciales) y agrega el header `WWW-Authenticate` para que el navegador muestre el prompt de inicio de sesión nuevamente:
|
||||
|
||||
{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}
|
||||
{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}
|
||||
|
||||
@@ -54,7 +54,7 @@ De la misma forma que con los modelos de Pydantic, declaras atributos de clase c
|
||||
|
||||
Puedes usar todas las mismas funcionalidades de validación y herramientas que usas para los modelos de Pydantic, como diferentes tipos de datos y validaciones adicionales con `Field()`.
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
|
||||
{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -70,7 +70,7 @@ Luego convertirá y validará los datos. Así que, cuando uses ese objeto `setti
|
||||
|
||||
Luego puedes usar el nuevo objeto `settings` en tu aplicación:
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *}
|
||||
{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}
|
||||
|
||||
### Ejecutar el servidor { #run-the-server }
|
||||
|
||||
@@ -104,11 +104,11 @@ Podrías poner esas configuraciones en otro archivo de módulo como viste en [Ap
|
||||
|
||||
Por ejemplo, podrías tener un archivo `config.py` con:
|
||||
|
||||
{* ../../docs_src/settings/app01_py39/config.py *}
|
||||
{* ../../docs_src/settings/app01_py310/config.py *}
|
||||
|
||||
Y luego usarlo en un archivo `main.py`:
|
||||
|
||||
{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *}
|
||||
{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -126,7 +126,7 @@ Esto podría ser especialmente útil durante las pruebas, ya que es muy fácil s
|
||||
|
||||
Proveniente del ejemplo anterior, tu archivo `config.py` podría verse como:
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py39/config.py hl[10] *}
|
||||
{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}
|
||||
|
||||
Nota que ahora no creamos un instance por defecto `settings = Settings()`.
|
||||
|
||||
@@ -134,7 +134,7 @@ Nota que ahora no creamos un instance por defecto `settings = Settings()`.
|
||||
|
||||
Ahora creamos una dependencia que devuelve un nuevo `config.Settings()`.
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py39/main.py hl[6,12:13] *}
|
||||
{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -146,13 +146,13 @@ Por ahora puedes asumir que `get_settings()` es una función normal.
|
||||
|
||||
Y luego podemos requerirlo desde la *path operation function* como una dependencia y usarlo donde lo necesitemos.
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py39/main.py hl[17,19:21] *}
|
||||
{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
|
||||
|
||||
### Configuraciones y pruebas { #settings-and-testing }
|
||||
|
||||
Luego sería muy fácil proporcionar un objeto de configuraciones diferente durante las pruebas al crear una sobrescritura de dependencia para `get_settings`:
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py39/test_main.py hl[9:10,13,21] *}
|
||||
{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}
|
||||
|
||||
En la sobrescritura de dependencia establecemos un nuevo valor para el `admin_email` al crear el nuevo objeto `Settings`, y luego devolvemos ese nuevo objeto.
|
||||
|
||||
@@ -193,7 +193,7 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
Y luego actualizar tu `config.py` con:
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
|
||||
{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -226,7 +226,7 @@ crearíamos ese objeto para cada request, y estaríamos leyendo el archivo `.env
|
||||
|
||||
Pero como estamos usando el decorador `@lru_cache` encima, el objeto `Settings` se creará solo una vez, la primera vez que se llame. ✔️
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *}
|
||||
{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
|
||||
|
||||
Entonces, para cualquier llamada subsiguiente de `get_settings()` en las dependencias de los próximos requests, en lugar de ejecutar el código interno de `get_settings()` y crear un nuevo objeto `Settings`, devolverá el mismo objeto que fue devuelto en la primera llamada, una y otra vez.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Si necesitas tener dos aplicaciones de **FastAPI** independientes, cada una con
|
||||
|
||||
Primero, crea la aplicación principal de nivel superior de **FastAPI**, y sus *path operations*:
|
||||
|
||||
{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *}
|
||||
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}
|
||||
|
||||
### Sub-aplicación { #sub-application }
|
||||
|
||||
@@ -18,7 +18,7 @@ Luego, crea tu sub-aplicación, y sus *path operations*.
|
||||
|
||||
Esta sub-aplicación es solo otra aplicación estándar de FastAPI, pero es la que se "montará":
|
||||
|
||||
{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *}
|
||||
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}
|
||||
|
||||
### Montar la sub-aplicación { #mount-the-sub-application }
|
||||
|
||||
@@ -26,7 +26,7 @@ En tu aplicación de nivel superior, `app`, monta la sub-aplicación, `subapi`.
|
||||
|
||||
En este caso, se montará en el path `/subapi`:
|
||||
|
||||
{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *}
|
||||
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}
|
||||
|
||||
### Revisa la documentación automática de la API { #check-the-automatic-api-docs }
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ $ pip install jinja2
|
||||
* Declara un parámetro `Request` en la *path operation* que devolverá una plantilla.
|
||||
* Usa los `templates` que creaste para renderizar y devolver un `TemplateResponse`, pasa el nombre de la plantilla, el objeto de request, y un diccionario "context" con pares clave-valor que se usarán dentro de la plantilla Jinja2.
|
||||
|
||||
{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *}
|
||||
{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
@@ -43,7 +43,7 @@ Al declarar `response_class=HTMLResponse`, la interfaz de usuario de la document
|
||||
|
||||
///
|
||||
|
||||
/// note | Nota Técnica
|
||||
/// note | Detalles técnicos
|
||||
|
||||
También podrías usar `from starlette.templating import Jinja2Templates`.
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ Un ejemplo podría ser que tienes un proveedor de autenticación externo al que
|
||||
|
||||
Le envías un token y te devuelve un usuario autenticado.
|
||||
|
||||
Este proveedor podría estar cobrándote por cada request, y llamarlo podría tomar más tiempo adicional que si tuvieras un usuario de prueba fijo para los tests.
|
||||
Este proveedor podría estar cobrándote por cada request, y llamarlo podría tomar más tiempo adicional que si tuvieras un usuario mock fijo para los tests.
|
||||
|
||||
Probablemente quieras probar el proveedor externo una vez, pero no necesariamente llamarlo para cada test que se realice.
|
||||
|
||||
En este caso, puedes sobrescribir la dependencia que llama a ese proveedor y usar una dependencia personalizada que devuelva un usuario de prueba, solo para tus tests.
|
||||
En este caso, puedes sobrescribir la dependencia que llama a ese proveedor y usar una dependencia personalizada que devuelva un usuario mock, solo para tus tests.
|
||||
|
||||
### Usa el atributo `app.dependency_overrides` { #use-the-app-dependency-overrides-attribute }
|
||||
|
||||
@@ -40,7 +40,7 @@ FastAPI todavía podrá sobrescribirla.
|
||||
|
||||
///
|
||||
|
||||
Entonces puedes restablecer las dependencias sobreescritas configurando `app.dependency_overrides` para que sea un `dict` vacío:
|
||||
Entonces puedes restablecer las dependencias sobreescritas (eliminarlas) configurando `app.dependency_overrides` para que sea un `dict` vacío:
|
||||
|
||||
```Python
|
||||
app.dependency_overrides = {}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
Cuando necesitas que `lifespan` se ejecute en tus tests, puedes usar el `TestClient` con un statement `with`:
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *}
|
||||
{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}
|
||||
|
||||
|
||||
Puedes leer más detalles sobre ["Ejecutar lifespan en tests en el sitio oficial de documentación de Starlette."](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)
|
||||
|
||||
Para los eventos obsoletos `startup` y `shutdown`, puedes usar el `TestClient` así:
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *}
|
||||
{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}
|
||||
|
||||
@@ -4,7 +4,7 @@ Puedes usar el mismo `TestClient` para probar WebSockets.
|
||||
|
||||
Para esto, usas el `TestClient` en un statement `with`, conectándote al WebSocket:
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *}
|
||||
{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ Imaginemos que quieres obtener la dirección IP/host del cliente dentro de tu *p
|
||||
|
||||
Para eso necesitas acceder al request directamente.
|
||||
|
||||
{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *}
|
||||
{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}
|
||||
|
||||
Al declarar un parámetro de *path operation function* con el tipo siendo `Request`, **FastAPI** sabrá pasar el `Request` en ese parámetro.
|
||||
|
||||
|
||||
@@ -38,13 +38,13 @@ En producción tendrías una de las opciones anteriores.
|
||||
|
||||
Pero es la forma más sencilla de enfocarse en el lado del servidor de WebSockets y tener un ejemplo funcional:
|
||||
|
||||
{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *}
|
||||
{* ../../docs_src/websockets/tutorial001_py310.py hl[2,6:38,41:43] *}
|
||||
|
||||
## Crear un `websocket` { #create-a-websocket }
|
||||
|
||||
En tu aplicación de **FastAPI**, crea un `websocket`:
|
||||
|
||||
{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *}
|
||||
{* ../../docs_src/websockets/tutorial001_py310.py hl[1,46:47] *}
|
||||
|
||||
/// note | Detalles Técnicos
|
||||
|
||||
@@ -58,7 +58,7 @@ También podrías usar `from starlette.websockets import WebSocket`.
|
||||
|
||||
En tu ruta de WebSocket puedes `await` para recibir mensajes y enviar mensajes.
|
||||
|
||||
{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *}
|
||||
{* ../../docs_src/websockets/tutorial001_py310.py hl[48:52] *}
|
||||
|
||||
Puedes recibir y enviar datos binarios, de texto y JSON.
|
||||
|
||||
@@ -154,7 +154,7 @@ Con eso puedes conectar el WebSocket y luego enviar y recibir mensajes:
|
||||
|
||||
Cuando una conexión de WebSocket se cierra, el `await websocket.receive_text()` lanzará una excepción `WebSocketDisconnect`, que puedes capturar y manejar como en este ejemplo.
|
||||
|
||||
{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
|
||||
{* ../../docs_src/websockets/tutorial003_py310.py hl[79:81] *}
|
||||
|
||||
Para probarlo:
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Luego envuelve la aplicación WSGI (p. ej., Flask) con el middleware.
|
||||
|
||||
Y luego móntala bajo un path.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Es el framework más popular de Python y es ampliamente confiable. Se utiliza pa
|
||||
|
||||
Está relativamente acoplado con bases de datos relacionales (como MySQL o PostgreSQL), por lo que tener una base de datos NoSQL (como Couchbase, MongoDB, Cassandra, etc) como motor de almacenamiento principal no es muy fácil.
|
||||
|
||||
Fue creado para generar el HTML en el backend, no para crear APIs utilizadas por un frontend moderno (como React, Vue.js y Angular) o por otros sistemas (como dispositivos del <abbr title="Internet of Things – Internet de las cosas">IoT</abbr>) comunicándose con él.
|
||||
Fue creado para generar el HTML en el backend, no para crear APIs utilizadas por un frontend moderno (como React, Vue.js y Angular) o por otros sistemas (como dispositivos del <abbr title="Internet of Things - Internet de las cosas">IoT</abbr>) comunicándose con él.
|
||||
|
||||
### <a href="https://www.django-rest-framework.org/" class="external-link" target="_blank">Django REST Framework</a> { #django-rest-framework }
|
||||
|
||||
@@ -76,7 +76,7 @@ Aun así, FastAPI se inspiró bastante en Requests.
|
||||
|
||||
Están, más o menos, en extremos opuestos, complementándose entre sí.
|
||||
|
||||
Requests tiene un diseño muy simple e intuitivo, es muy fácil de usar, con valores predeterminados sensatos. Pero al mismo tiempo, es muy poderoso y personalizable.
|
||||
Requests tiene un diseño muy simple e intuitivo, es muy fácil de usar, con valores por defecto sensatos. Pero al mismo tiempo, es muy poderoso y personalizable.
|
||||
|
||||
Por eso, como se dice en el sitio web oficial:
|
||||
|
||||
@@ -102,7 +102,7 @@ Mira las similitudes entre `requests.get(...)` y `@app.get(...)`.
|
||||
|
||||
* Tener un API simple e intuitivo.
|
||||
* Usar nombres de métodos HTTP (operaciones) directamente, de una manera sencilla e intuitiva.
|
||||
* Tener valores predeterminados sensatos, pero personalizaciones poderosas.
|
||||
* Tener valores por defecto sensatos, pero personalizaciones poderosas.
|
||||
|
||||
///
|
||||
|
||||
@@ -137,7 +137,7 @@ Existen varios frameworks REST para Flask, pero después de invertir tiempo y tr
|
||||
|
||||
### <a href="https://marshmallow.readthedocs.io/en/stable/" class="external-link" target="_blank">Marshmallow</a> { #marshmallow }
|
||||
|
||||
Una de las principales funcionalidades necesitadas por los sistemas API es la "<abbr title="también llamada marshalling, conversión">serialización</abbr>" de datos, que consiste en tomar datos del código (Python) y convertirlos en algo que pueda ser enviado a través de la red. Por ejemplo, convertir un objeto que contiene datos de una base de datos en un objeto JSON. Convertir objetos `datetime` en strings, etc.
|
||||
Una de las principales funcionalidades necesitadas por los sistemas API es la "<dfn title="también llamado marshalling, conversión">serialización</dfn>" de datos, que consiste en tomar datos del código (Python) y convertirlos en algo que pueda ser enviado a través de la red. Por ejemplo, convertir un objeto que contiene datos de una base de datos en un objeto JSON. Convertir objetos `datetime` en strings, etc.
|
||||
|
||||
Otra gran funcionalidad necesaria por las APIs es la validación de datos, asegurarse de que los datos sean válidos, dados ciertos parámetros. Por ejemplo, que algún campo sea un `int`, y no algún string aleatorio. Esto es especialmente útil para los datos entrantes.
|
||||
|
||||
@@ -145,7 +145,7 @@ Sin un sistema de validación de datos, tendrías que hacer todas las comprobaci
|
||||
|
||||
Estas funcionalidades son para lo que fue creado Marshmallow. Es un gran paquete, y lo he usado mucho antes.
|
||||
|
||||
Pero fue creado antes de que existieran las anotaciones de tipos en Python. Así que, para definir cada <abbr title="la definición de cómo deberían formarse los datos">esquema</abbr> necesitas usar utilidades y clases específicas proporcionadas por Marshmallow.
|
||||
Pero fue creado antes de que existieran las anotaciones de tipos en Python. Así que, para definir cada <dfn title="la definición de cómo deberían formarse los datos">esquema</dfn> necesitas usar utilidades y clases específicas proporcionadas por Marshmallow.
|
||||
|
||||
/// check | Inspiró a **FastAPI** a
|
||||
|
||||
@@ -155,7 +155,7 @@ Usar código para definir "esquemas" que proporcionen tipos de datos y validaci
|
||||
|
||||
### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a> { #webargs }
|
||||
|
||||
Otra gran funcionalidad requerida por las APIs es el <abbr title="lectura y conversión a datos de Python">parse</abbr> de datos de las requests entrantes.
|
||||
Otra gran funcionalidad requerida por las APIs es el <dfn title="lectura y conversión a datos de Python">parsing</dfn> de datos de las requests entrantes.
|
||||
|
||||
Webargs es una herramienta que fue creada para proporcionar esa funcionalidad sobre varios frameworks, incluido Flask.
|
||||
|
||||
@@ -177,7 +177,7 @@ Tener validación automática de datos entrantes en una request.
|
||||
|
||||
### <a href="https://apispec.readthedocs.io/en/stable/" class="external-link" target="_blank">APISpec</a> { #apispec }
|
||||
|
||||
Marshmallow y Webargs proporcionan validación, parse y serialización como plug-ins.
|
||||
Marshmallow y Webargs proporcionan validación, parsing y serialización como plug-ins.
|
||||
|
||||
Pero la documentación todavía falta. Entonces APISpec fue creado.
|
||||
|
||||
@@ -419,7 +419,7 @@ Manejar toda la validación de datos, serialización de datos y documentación a
|
||||
|
||||
### <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> { #starlette }
|
||||
|
||||
Starlette es un framework/toolkit <abbr title="The new standard for building asynchronous Python web applications – El nuevo estándar para construir aplicaciones web asíncronas en Python">ASGI</abbr> liviano, ideal para construir servicios asyncio de alto rendimiento.
|
||||
Starlette es un framework/toolkit <dfn title="El nuevo estándar para construir aplicaciones web asíncronas en Python">ASGI</dfn> liviano, ideal para construir servicios asyncio de alto rendimiento.
|
||||
|
||||
Es muy simple e intuitivo. Está diseñado para ser fácilmente extensible y tener componentes modulares.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Detalles sobre la sintaxis `async def` para *path operation functions* y algunos
|
||||
|
||||
## ¿Con prisa? { #in-a-hurry }
|
||||
|
||||
<abbr title="too long; didn't read"><strong>TL;DR:</strong></abbr>
|
||||
<abbr title="too long; didn't read - demasiado largo; no lo leí"><strong>TL;DR:</strong></abbr>
|
||||
|
||||
Si estás usando paquetes de terceros que te dicen que los llames con `await`, como:
|
||||
|
||||
@@ -74,7 +74,7 @@ Luego la computadora / programa 🤖 volverá cada vez que tenga una oportunidad
|
||||
|
||||
Después, 🤖 toma la primera tarea que termine (digamos, nuestro "archivo-lento" 📝) y continúa con lo que tenía que hacer con ella.
|
||||
|
||||
Ese "esperar otra cosa" normalmente se refiere a las operaciones de <abbr title="Input and Output – Entrada y salida">I/O</abbr> que son relativamente "lentas" (comparadas con la velocidad del procesador y la memoria RAM), como esperar:
|
||||
Ese "esperar otra cosa" normalmente se refiere a las operaciones de <abbr title="Input and Output - Entrada y salida">I/O</abbr> que son relativamente "lentas" (comparadas con la velocidad del procesador y la memoria RAM), como esperar:
|
||||
|
||||
* que los datos del cliente se envíen a través de la red
|
||||
* que los datos enviados por tu programa sean recibidos por el cliente a través de la red
|
||||
@@ -85,7 +85,7 @@ Ese "esperar otra cosa" normalmente se refiere a las operaciones de <abbr title=
|
||||
* que una query de base de datos devuelva los resultados
|
||||
* etc.
|
||||
|
||||
Como el tiempo de ejecución se consume principalmente esperando operaciones de <abbr title="Input and Output – Entrada y salida">I/O</abbr>, las llaman operaciones "I/O bound".
|
||||
Como el tiempo de ejecución se consume principalmente esperando operaciones de <abbr title="Input and Output - Entrada y salida">I/O</abbr>, las llaman operaciones "I/O bound".
|
||||
|
||||
Se llama "asíncrono" porque la computadora / programa no tiene que estar "sincronizado" con la tarea lenta, esperando el momento exacto en que la tarea termine, sin hacer nada, para poder tomar el resultado de la tarea y continuar el trabajo.
|
||||
|
||||
@@ -277,7 +277,7 @@ Pero en este caso, si pudieras traer a los 8 ex-cajeros/cocineros/ahora-limpiado
|
||||
|
||||
En este escenario, cada uno de los limpiadores (incluyéndote) sería un procesador, haciendo su parte del trabajo.
|
||||
|
||||
Y como la mayor parte del tiempo de ejecución se dedica al trabajo real (en lugar de esperar), y el trabajo en una computadora lo realiza una <abbr title="Central Processing Unit – Unidad Central de Procesamiento">CPU</abbr>, llaman a estos problemas "CPU bound".
|
||||
Y como la mayor parte del tiempo de ejecución se dedica al trabajo real (en lugar de esperar), y el trabajo en una computadora lo realiza una <abbr title="Central Processing Unit - Unidad Central de Procesamiento">CPU</abbr>, llaman a estos problemas "CPU bound".
|
||||
|
||||
---
|
||||
|
||||
@@ -417,7 +417,7 @@ Si tienes bastante conocimiento técnico (coroutines, hilos, bloqueo, etc.) y ti
|
||||
|
||||
Cuando declaras una *path operation function* con `def` normal en lugar de `async def`, se ejecuta en un threadpool externo que luego es esperado, en lugar de ser llamado directamente (ya que bloquearía el servidor).
|
||||
|
||||
Si vienes de otro framework async que no funciona de la manera descrita anteriormente y estás acostumbrado a definir funciones de *path operation* solo de cómputo trivial con `def` normal para una pequeña ganancia de rendimiento (alrededor de 100 nanosegundos), ten en cuenta que en **FastAPI** el efecto sería bastante opuesto. En estos casos, es mejor usar `async def` a menos que tus *path operation functions* usen código que realice <abbr title="Input/Output – Entrada/Salida: lectura o escritura en disco, comunicaciones de red.">I/O</abbr> de bloqueo.
|
||||
Si vienes de otro framework async que no funciona de la manera descrita anteriormente y estás acostumbrado a definir funciones de *path operation* solo de cómputo trivial con `def` normal para una pequeña ganancia de rendimiento (alrededor de 100 nanosegundos), ten en cuenta que en **FastAPI** el efecto sería bastante opuesto. En estos casos, es mejor usar `async def` a menos que tus *path operation functions* usen código que realice <abbr title="Input/Output - Entrada/Salida: lectura o escritura en disco, comunicaciones de red.">I/O</abbr> de bloqueo.
|
||||
|
||||
Aun así, en ambas situaciones, es probable que **FastAPI** [siga siendo más rápida](index.md#performance){.internal-link target=_blank} que (o al menos comparable a) tu framework anterior.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ En la mayoría de los casos, los principales proveedores de nube tienen guías p
|
||||
|
||||
Simplifica el proceso de **construir**, **desplegar** y **acceder** a una API con un esfuerzo mínimo.
|
||||
|
||||
Trae la misma experiencia de desarrollador de construir aplicaciones con FastAPI a desplegarlas en la nube. 🎉
|
||||
Trae la misma **experiencia de desarrollador** de construir aplicaciones con FastAPI a **desplegarlas** en la nube. 🎉
|
||||
|
||||
FastAPI Cloud es el sponsor principal y proveedor de financiamiento de los proyectos open source *FastAPI and friends*. ✨
|
||||
|
||||
|
||||
@@ -318,4 +318,4 @@ Has estado leyendo aquí algunos de los conceptos principales que probablemente
|
||||
|
||||
Comprender estas ideas y cómo aplicarlas debería darte la intuición necesaria para tomar decisiones al configurar y ajustar tus implementaciones. 🤓
|
||||
|
||||
En las próximas secciones, te daré ejemplos más concretos de posibles estrategias que puedes seguir. 🚀
|
||||
En las próximas secciones, te daré más ejemplos concretos de posibles estrategias que puedes seguir. 🚀
|
||||
|
||||
@@ -14,7 +14,7 @@ Usar contenedores de Linux tiene varias ventajas, incluyendo **seguridad**, **re
|
||||
<summary>Vista previa del Dockerfile 👀</summary>
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.9
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
@@ -166,7 +166,7 @@ Ahora, en el mismo directorio del proyecto, crea un archivo `Dockerfile` con:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)!
|
||||
FROM python:3.9
|
||||
FROM python:3.14
|
||||
|
||||
# (2)!
|
||||
WORKDIR /code
|
||||
@@ -390,7 +390,7 @@ Si tu FastAPI es un solo archivo, por ejemplo, `main.py` sin un directorio `./ap
|
||||
Entonces solo tendrías que cambiar las rutas correspondientes para copiar el archivo dentro del `Dockerfile`:
|
||||
|
||||
```{ .dockerfile .annotate hl_lines="10 13" }
|
||||
FROM python:3.9
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
@@ -454,7 +454,7 @@ Sin usar contenedores, hacer que las aplicaciones se ejecuten al inicio y con re
|
||||
|
||||
## Replicación - Número de Procesos { #replication-number-of-processes }
|
||||
|
||||
Si tienes un <abbr title="Un grupo de máquinas que están configuradas para estar conectadas y trabajar juntas de alguna manera.">cluster</abbr> de máquinas con **Kubernetes**, Docker Swarm Mode, Nomad, u otro sistema complejo similar para gestionar contenedores distribuidos en varias máquinas, entonces probablemente querrás manejar la **replicación** a nivel de **cluster** en lugar de usar un **gestor de procesos** (como Uvicorn con workers) en cada contenedor.
|
||||
Si tienes un <dfn title="Un grupo de máquinas que están configuradas para estar conectadas y trabajar juntas de alguna manera.">clúster</dfn> de máquinas con **Kubernetes**, Docker Swarm Mode, Nomad, u otro sistema complejo similar para gestionar contenedores distribuidos en varias máquinas, entonces probablemente querrás manejar la **replicación** a nivel de **cluster** en lugar de usar un **gestor de procesos** (como Uvicorn con workers) en cada contenedor.
|
||||
|
||||
Uno de esos sistemas de gestión de contenedores distribuidos como Kubernetes normalmente tiene alguna forma integrada de manejar la **replicación de contenedores** mientras aún soporta el **load balancing** para las requests entrantes. Todo a nivel de **cluster**.
|
||||
|
||||
@@ -499,7 +499,7 @@ Por supuesto, hay **casos especiales** donde podrías querer tener **un contened
|
||||
En esos casos, puedes usar la opción de línea de comandos `--workers` para establecer el número de workers que deseas ejecutar:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
FROM python:3.9
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# FastAPI Cloud { #fastapi-cloud }
|
||||
|
||||
Puedes desplegar tu app de FastAPI en <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> con un solo comando; ve y únete a la lista de espera si aún no lo has hecho. 🚀
|
||||
Puedes desplegar tu app de FastAPI en <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> con **un solo comando**; ve y únete a la lista de espera si aún no lo has hecho. 🚀
|
||||
|
||||
## Iniciar sesión { #login }
|
||||
|
||||
@@ -20,7 +20,7 @@ You are logged in to FastAPI Cloud 🚀
|
||||
|
||||
## Desplegar { #deploy }
|
||||
|
||||
Ahora despliega tu app, con un solo comando:
|
||||
Ahora despliega tu app, con **un solo comando**:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ Aquí tienes un ejemplo de cómo podría ser una API HTTPS, paso a paso, prestan
|
||||
|
||||
Probablemente todo comenzaría adquiriendo un **nombre de dominio**. Luego, lo configurarías en un servidor DNS (posiblemente tu mismo proveedor de la nube).
|
||||
|
||||
Probablemente conseguirías un servidor en la nube (una máquina virtual) o algo similar, y tendría una **dirección IP pública** <abbr title="Que no cambia">fija</abbr>.
|
||||
Probablemente conseguirías un servidor en la nube (una máquina virtual) o algo similar, y tendría una **dirección IP pública** <dfn title="No cambia con el tiempo. No dinámica.">fija</dfn>.
|
||||
|
||||
En el/los servidor(es) DNS configurarías un registro (un "`A record`") para apuntar **tu dominio** a la **dirección IP pública de tu servidor**.
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ Podrías usar ese comando, por ejemplo, para iniciar tu app **FastAPI** en un co
|
||||
|
||||
Vamos a profundizar un poquito en los detalles.
|
||||
|
||||
FastAPI usa un estándar para construir frameworks de web y servidores de Python llamado <abbr title="Asynchronous Server Gateway Interface – Interfaz de puerta de enlace de servidor asíncrona">ASGI</abbr>. FastAPI es un framework web ASGI.
|
||||
FastAPI usa un estándar para construir frameworks de web y servidores de Python llamado <abbr title="Asynchronous Server Gateway Interface - Interfaz de puerta de enlace de servidor asíncrona">ASGI</abbr>. FastAPI es un framework web ASGI.
|
||||
|
||||
Lo principal que necesitas para ejecutar una aplicación **FastAPI** (o cualquier otra aplicación ASGI) en una máquina de servidor remota es un programa de servidor ASGI como **Uvicorn**, que es el que viene por defecto en el comando `fastapi`.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
### Basado en estándares abiertos { #based-on-open-standards }
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> para la creación de APIs, incluyendo declaraciones de <abbr title="también conocido como: endpoints, rutas">path</abbr> <abbr title="también conocido como métodos HTTP, como POST, GET, PUT, DELETE">operations</abbr>, parámetros, request bodies, seguridad, etc.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> para la creación de APIs, incluyendo declaraciones de <dfn title="también conocido como: endpoints, rutas">path</dfn> <dfn title="también conocido como métodos HTTP, como POST, GET, PUT, DELETE">operations</dfn>, parámetros, request bodies, seguridad, etc.
|
||||
* Documentación automática de modelos de datos con <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (ya que OpenAPI en sí mismo está basado en JSON Schema).
|
||||
* Diseñado alrededor de estos estándares, tras un estudio meticuloso. En lugar de ser una capa adicional.
|
||||
* Esto también permite el uso de **generación de código cliente automática** en muchos idiomas.
|
||||
@@ -105,8 +105,8 @@ Pero por defecto, todo **"simplemente funciona"**.
|
||||
|
||||
* Validación para la mayoría (¿o todas?) de los **tipos de datos** de Python, incluyendo:
|
||||
* Objetos JSON (`dict`).
|
||||
* Array JSON (`list`) definiendo tipos de elementos.
|
||||
* Campos de cadena de caracteres (`str`), definiendo longitudes mínimas y máximas.
|
||||
* array JSON (`list`) definiendo tipos de elementos.
|
||||
* Campos de string (`str`), definiendo longitudes mínimas y máximas.
|
||||
* Números (`int`, `float`) con valores mínimos y máximos, etc.
|
||||
|
||||
* Validación para tipos más exóticos, como:
|
||||
@@ -136,7 +136,7 @@ Todo construido como herramientas y componentes reutilizables que son fáciles d
|
||||
|
||||
### Inyección de dependencias { #dependency-injection }
|
||||
|
||||
FastAPI incluye un sistema de <abbr title='también conocido como "componentes", "recursos", "servicios", "proveedores"'><strong>Inyección de Dependencias</strong></abbr> extremadamente fácil de usar, pero extremadamente potente.
|
||||
FastAPI incluye un sistema de <dfn title='también conocido como "componentes", "recursos", "servicios", "proveedores"'><strong>Inyección de Dependencias</strong></dfn> extremadamente fácil de usar, pero extremadamente potente.
|
||||
|
||||
* Incluso las dependencias pueden tener dependencias, creando una jerarquía o **"grafo de dependencias"**.
|
||||
* Todo **manejado automáticamente** por el framework.
|
||||
@@ -153,8 +153,8 @@ Cualquier integración está diseñada para ser tan simple de usar (con dependen
|
||||
|
||||
### Probado { #tested }
|
||||
|
||||
* 100% de <abbr title="La cantidad de código que se prueba automáticamente">cobertura de tests</abbr>.
|
||||
* 100% <abbr title="Anotaciones de tipos en Python, con esto tu editor y herramientas externas pueden ofrecerte mejor soporte">anotada con tipos</abbr> code base.
|
||||
* 100% de <dfn title="La cantidad de código que se prueba automáticamente">cobertura de tests</dfn>.
|
||||
* 100% <dfn title="Anotaciones de tipos en Python, con esto tu editor y herramientas externas pueden ofrecerte mejor soporte">anotada con tipos</dfn> code base.
|
||||
* Usado en aplicaciones en producción.
|
||||
|
||||
## Funcionalidades de Starlette { #starlette-features }
|
||||
@@ -173,7 +173,7 @@ Con **FastAPI** obtienes todas las funcionalidades de **Starlette** (ya que Fast
|
||||
* **CORS**, GZip, archivos estáticos, responses en streaming.
|
||||
* Soporte para **Session y Cookie**.
|
||||
* Cobertura de tests del 100%.
|
||||
* code base completamente anotada con tipos.
|
||||
* code base 100% anotada con tipos.
|
||||
|
||||
## Funcionalidades de Pydantic { #pydantic-features }
|
||||
|
||||
@@ -190,7 +190,7 @@ Con **FastAPI** obtienes todas las funcionalidades de **Pydantic** (ya que FastA
|
||||
* **Sin complicaciones**:
|
||||
* Sin micro-lenguaje de definición de esquemas nuevo que aprender.
|
||||
* Si conoces los tipos en Python sabes cómo usar Pydantic.
|
||||
* Se lleva bien con tu **<abbr title="Integrated Development Environment – Entorno de Desarrollo Integrado: similar a un editor de código">IDE</abbr>/<abbr title="Un programa que verifica errores de código">linter</abbr>/cerebro**:
|
||||
* Se lleva bien con tu **<abbr title="Integrated Development Environment – Entorno de Desarrollo Integrado: similar a un editor de código">IDE</abbr>/<dfn title="Un programa que verifica errores de código">linter</dfn>/cerebro**:
|
||||
* Porque las estructuras de datos de pydantic son solo instances de clases que defines; autocompletado, linting, mypy y tu intuición deberían funcionar correctamente con tus datos validados.
|
||||
* Valida **estructuras complejas**:
|
||||
* Uso de modelos jerárquicos de Pydantic, `List` y `Dict` de `typing` de Python, etc.
|
||||
|
||||
@@ -110,7 +110,7 @@ En muchos casos solo copiarán un fragmento del código, pero eso no es suficien
|
||||
|
||||
### Sugerir soluciones { #suggest-solutions }
|
||||
|
||||
* Después de poder entender la pregunta, puedes darles un posible **respuesta**.
|
||||
* Después de poder entender la pregunta, puedes darles una posible **respuesta**.
|
||||
|
||||
* En muchos casos, es mejor entender su **problema subyacente o caso de uso**, porque podría haber una mejor manera de resolverlo que lo que están intentando hacer.
|
||||
|
||||
@@ -247,9 +247,9 @@ Las conversaciones en los sistemas de chat tampoco son tan fácilmente buscables
|
||||
|
||||
Por otro lado, hay miles de usuarios en los sistemas de chat, por lo que hay muchas posibilidades de que encuentres a alguien con quien hablar allí, casi todo el tiempo. 😄
|
||||
|
||||
## Patrocina al autor { #sponsor-the-author }
|
||||
## Hazte sponsor del autor { #sponsor-the-author }
|
||||
|
||||
Si tu **producto/empresa** depende de o está relacionado con **FastAPI** y quieres llegar a sus usuarios, puedes patrocinar al autor (a mí) a través de <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>. Según el nivel, podrías obtener algunos beneficios extra, como una insignia en la documentación. 🎁
|
||||
Si tu **producto/empresa** depende de o está relacionado con **FastAPI** y quieres llegar a sus usuarios, puedes hacerte sponsor del autor (de mí) a través de <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>. Según el nivel, podrías obtener algunos beneficios extra, como una insignia en la documentación. 🎁
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Pero si por alguna razón tus clientes dependen del comportamiento anterior, pue
|
||||
|
||||
Por ejemplo, puedes crear una subclase de `HTTPBearer` que devuelva un error `403 Forbidden` en lugar del `401 Unauthorized` por defecto:
|
||||
|
||||
{* ../../docs_src/authentication_error_status_code/tutorial001_an_py39.py hl[9:13] *}
|
||||
{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ Puedes usar fácilmente las mismas configuraciones de Pydantic para configurar t
|
||||
|
||||
Por ejemplo:
|
||||
|
||||
{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *}
|
||||
{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
|
||||
|
||||
Aquí declaramos la configuración `openapi_url` con el mismo valor por defecto de `"/openapi.json"`.
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Sin cambiar la configuración, el resaltado de sintaxis está activado por defec
|
||||
|
||||
Pero puedes desactivarlo estableciendo `syntaxHighlight` en `False`:
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *}
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
|
||||
|
||||
...y entonces Swagger UI ya no mostrará el resaltado de sintaxis:
|
||||
|
||||
@@ -28,17 +28,17 @@ Pero puedes desactivarlo estableciendo `syntaxHighlight` en `False`:
|
||||
|
||||
De la misma manera, podrías configurar el tema del resaltado de sintaxis con la clave `"syntaxHighlight.theme"` (ten en cuenta que tiene un punto en el medio):
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *}
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
|
||||
|
||||
Esa configuración cambiaría el tema de color del resaltado de sintaxis:
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image04.png">
|
||||
|
||||
## Cambiar los parámetros predeterminados de Swagger UI { #change-default-swagger-ui-parameters }
|
||||
## Cambiar los parámetros por defecto de Swagger UI { #change-default-swagger-ui-parameters }
|
||||
|
||||
FastAPI incluye algunos parámetros de configuración predeterminados apropiados para la mayoría de los casos de uso.
|
||||
FastAPI incluye algunos parámetros de configuración por defecto apropiados para la mayoría de los casos de uso.
|
||||
|
||||
Incluye estas configuraciones predeterminadas:
|
||||
Incluye estas configuraciones por defecto:
|
||||
|
||||
{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}
|
||||
|
||||
@@ -46,7 +46,7 @@ Puedes sobrescribir cualquiera de ellos estableciendo un valor diferente en el a
|
||||
|
||||
Por ejemplo, para desactivar `deepLinking` podrías pasar estas configuraciones a `swagger_ui_parameters`:
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *}
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
|
||||
|
||||
## Otros parámetros de Swagger UI { #other-swagger-ui-parameters }
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ El primer paso es desactivar la documentación automática, ya que por defecto,
|
||||
|
||||
Para desactivarlos, establece sus URLs en `None` cuando crees tu aplicación de `FastAPI`:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *}
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
|
||||
|
||||
### Incluye la documentación personalizada { #include-the-custom-docs }
|
||||
|
||||
@@ -34,7 +34,7 @@ Puedes reutilizar las funciones internas de FastAPI para crear las páginas HTML
|
||||
|
||||
Y de manera similar para ReDoc...
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *}
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -50,7 +50,7 @@ Swagger UI lo manejará detrás de escena para ti, pero necesita este auxiliar d
|
||||
|
||||
Ahora, para poder probar que todo funciona, crea una *path operation*:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *}
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
|
||||
|
||||
### Pruébalo { #test-it }
|
||||
|
||||
@@ -118,7 +118,7 @@ Después de eso, tu estructura de archivos podría verse así:
|
||||
* Importa `StaticFiles`.
|
||||
* "Monta" una instance de `StaticFiles()` en un path específico.
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *}
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
|
||||
|
||||
### Prueba los archivos estáticos { #test-the-static-files }
|
||||
|
||||
@@ -144,7 +144,7 @@ Igual que cuando usas un CDN personalizado, el primer paso es desactivar la docu
|
||||
|
||||
Para desactivarlos, establece sus URLs en `None` cuando crees tu aplicación de `FastAPI`:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *}
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
|
||||
|
||||
### Incluye la documentación personalizada para archivos estáticos { #include-the-custom-docs-for-static-files }
|
||||
|
||||
@@ -160,7 +160,7 @@ Nuevamente, puedes reutilizar las funciones internas de FastAPI para crear las p
|
||||
|
||||
Y de manera similar para ReDoc...
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *}
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -176,7 +176,7 @@ Swagger UI lo manejará detrás de escena para ti, pero necesita este auxiliar d
|
||||
|
||||
Ahora, para poder probar que todo funciona, crea una *path operation*:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *}
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
|
||||
|
||||
### Prueba la UI de Archivos Estáticos { #test-static-files-ui }
|
||||
|
||||
|
||||
@@ -43,19 +43,19 @@ Por ejemplo, vamos a añadir <a href="https://github.com/Rebilly/ReDoc/blob/mast
|
||||
|
||||
Primero, escribe toda tu aplicación **FastAPI** como normalmente:
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[1,4,7:9] *}
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
|
||||
|
||||
### Generar el esquema de OpenAPI { #generate-the-openapi-schema }
|
||||
|
||||
Luego, usa la misma función de utilidad para generar el esquema de OpenAPI, dentro de una función `custom_openapi()`:
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[2,15:21] *}
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
|
||||
|
||||
### Modificar el esquema de OpenAPI { #modify-the-openapi-schema }
|
||||
|
||||
Ahora puedes añadir la extensión de ReDoc, agregando un `x-logo` personalizado al "objeto" `info` en el esquema de OpenAPI:
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[22:24] *}
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
|
||||
|
||||
### Cachear el esquema de OpenAPI { #cache-the-openapi-schema }
|
||||
|
||||
@@ -65,13 +65,13 @@ De esa forma, tu aplicación no tendrá que generar el esquema cada vez que un u
|
||||
|
||||
Se generará solo una vez, y luego se usará el mismo esquema cacheado para las siguientes requests.
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[13:14,25:26] *}
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
|
||||
|
||||
### Sobrescribir el método { #override-the-method }
|
||||
|
||||
Ahora puedes reemplazar el método `.openapi()` por tu nueva función.
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[29] *}
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
|
||||
|
||||
### Revisa { #check-it }
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ Dependiendo de tu caso de uso, podrías preferir usar un paquete diferente, pero
|
||||
|
||||
Aquí tienes una pequeña vista previa de cómo podrías integrar Strawberry con FastAPI:
|
||||
|
||||
{* ../../docs_src/graphql_/tutorial001_py39.py hl[3,22,25] *}
|
||||
{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
|
||||
|
||||
Puedes aprender más sobre Strawberry en la <a href="https://strawberry.rocks/" class="external-link" target="_blank">documentación de Strawberry</a>.
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ Probablemente el caso principal para esto es si ya tienes algún código cliente
|
||||
|
||||
En ese caso, puedes desactivar esta funcionalidad en **FastAPI**, con el parámetro `separate_input_output_schemas=False`.
|
||||
|
||||
/// info
|
||||
/// info | Información
|
||||
|
||||
El soporte para `separate_input_output_schemas` fue agregado en FastAPI `0.102.0`. 🤓
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Probando una Base de Datos { #testing-a-database }
|
||||
# Escribiendo pruebas para una base de datos { #testing-a-database }
|
||||
|
||||
Puedes estudiar sobre bases de datos, SQL y SQLModel en la <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">documentación de SQLModel</a>. 🤓
|
||||
|
||||
Hay un mini <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">tutorial sobre el uso de SQLModel con FastAPI</a>. ✨
|
||||
|
||||
Ese tutorial incluye una sección sobre <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/" class="external-link" target="_blank">cómo probar bases de datos SQL</a>. 😎
|
||||
Ese tutorial incluye una sección sobre <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/" class="external-link" target="_blank">escribir pruebas para bases de datos SQL</a>. 😎
|
||||
|
||||
@@ -40,7 +40,7 @@ Las funcionalidades clave son:
|
||||
* **Rápido**: Muy alto rendimiento, a la par con **NodeJS** y **Go** (gracias a Starlette y Pydantic). [Uno de los frameworks Python más rápidos disponibles](#performance).
|
||||
* **Rápido de programar**: Aumenta la velocidad para desarrollar funcionalidades en aproximadamente un 200% a 300%. *
|
||||
* **Menos bugs**: Reduce en aproximadamente un 40% los errores inducidos por humanos (desarrolladores). *
|
||||
* **Intuitivo**: Gran soporte para editores. <abbr title="también conocido como auto-complete, autocompletado, IntelliSense">Autocompletado</abbr> en todas partes. Menos tiempo depurando.
|
||||
* **Intuitivo**: Gran soporte para editores. <dfn title="también conocido como: autocompletado, IntelliSense">Autocompletado</dfn> en todas partes. Menos tiempo depurando.
|
||||
* **Fácil**: Diseñado para ser fácil de usar y aprender. Menos tiempo leyendo documentación.
|
||||
* **Corto**: Minimiza la duplicación de código. Múltiples funcionalidades desde cada declaración de parámetro. Menos bugs.
|
||||
* **Robusto**: Obtén código listo para producción. Con documentación interactiva automática.
|
||||
@@ -368,7 +368,7 @@ item: Item
|
||||
* Validación de datos:
|
||||
* Errores automáticos y claros cuando los datos son inválidos.
|
||||
* Validación incluso para objetos JSON profundamente anidados.
|
||||
* <abbr title="también conocido como: serialización, parsing, marshalling">Conversión</abbr> de datos de entrada: de la red a los datos y tipos de Python. Leyendo desde:
|
||||
* <dfn title="también conocido como: serialización, parsing, marshalling">Conversión</dfn> de datos de entrada: de la red a los datos y tipos de Python. Leyendo desde:
|
||||
* JSON.
|
||||
* Parámetros de path.
|
||||
* Parámetros de query.
|
||||
@@ -376,7 +376,7 @@ item: Item
|
||||
* Headers.
|
||||
* Forms.
|
||||
* Archivos.
|
||||
* <abbr title="también conocido como: serialización, parsing, marshalling">Conversión</abbr> de datos de salida: convirtiendo de datos y tipos de Python a datos de red (como JSON):
|
||||
* <dfn title="también conocido como: serialización, parsing, marshalling">Conversión</dfn> de datos de salida: convirtiendo de datos y tipos de Python a datos de red (como JSON):
|
||||
* Convertir tipos de Python (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
* Objetos `datetime`.
|
||||
* Objetos `UUID`.
|
||||
@@ -439,7 +439,7 @@ Para un ejemplo más completo incluyendo más funcionalidades, ve al <a href="ht
|
||||
|
||||
* Declaración de **parámetros** desde otros lugares diferentes como: **headers**, **cookies**, **campos de formulario** y **archivos**.
|
||||
* Cómo establecer **restricciones de validación** como `maximum_length` o `regex`.
|
||||
* Un sistema de **<abbr title="también conocido como componentes, recursos, proveedores, servicios, inyectables">Inyección de Dependencias</abbr>** muy poderoso y fácil de usar.
|
||||
* Un sistema de **<dfn title="también conocido como: componentes, recursos, proveedores, servicios, inyectables">Inyección de Dependencias</dfn>** muy poderoso y fácil de usar.
|
||||
* Seguridad y autenticación, incluyendo soporte para **OAuth2** con **tokens JWT** y autenticación **HTTP Basic**.
|
||||
* Técnicas más avanzadas (pero igualmente fáciles) para declarar **modelos JSON profundamente anidados** (gracias a Pydantic).
|
||||
* Integración con **GraphQL** usando <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> y otros paquetes.
|
||||
@@ -524,7 +524,7 @@ Usadas por Starlette:
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Requerido si deseas usar el `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Requerido si deseas usar la configuración de plantilla por defecto.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Requerido si deseas soportar <abbr title="convertir el string que viene de un request HTTP en datos de Python">"parsing"</abbr> de forms, con `request.form()`.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Requerido si deseas soportar form <dfn title="convertir el string que viene de un request HTTP en datos de Python">"parsing"</dfn>, con `request.form()`.
|
||||
|
||||
Usadas por FastAPI:
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Puedes usar esta plantilla para comenzar, ya que incluye gran parte de la config
|
||||
|
||||
Repositorio de GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Plantilla Full Stack FastAPI</a>
|
||||
|
||||
## Plantilla Full Stack FastAPI - Tecnología y Funcionalidades { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
## Plantilla Full Stack FastAPI - Stack de tecnología y funcionalidades { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
|
||||
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/es) para la API del backend en Python.
|
||||
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para las interacciones con bases de datos SQL en Python (ORM).
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Python tiene soporte para "anotaciones de tipos" opcionales (también llamadas "type hints").
|
||||
|
||||
Estas **"anotaciones de tipos"** o type hints son una sintaxis especial que permite declarar el <abbr title="por ejemplo: str, int, float, bool">tipo</abbr> de una variable.
|
||||
Estas **"anotaciones de tipos"** o type hints son una sintaxis especial que permite declarar el <dfn title="por ejemplo: str, int, float, bool">tipo</dfn> de una variable.
|
||||
|
||||
Al declarar tipos para tus variables, los editores y herramientas te pueden proporcionar un mejor soporte.
|
||||
|
||||
@@ -22,7 +22,7 @@ Si eres un experto en Python, y ya sabes todo sobre las anotaciones de tipos, sa
|
||||
|
||||
Comencemos con un ejemplo simple:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py *}
|
||||
{* ../../docs_src/python_types/tutorial001_py310.py *}
|
||||
|
||||
Llamar a este programa genera:
|
||||
|
||||
@@ -34,9 +34,9 @@ La función hace lo siguiente:
|
||||
|
||||
* Toma un `first_name` y `last_name`.
|
||||
* Convierte la primera letra de cada uno a mayúsculas con `title()`.
|
||||
* <abbr title="Los une, como uno. Con el contenido de uno después del otro.">Concatena</abbr> ambos con un espacio en el medio.
|
||||
* <dfn title="Los une, como uno. Con el contenido de uno después del otro.">Concatena</dfn> ambos con un espacio en el medio.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
|
||||
{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
|
||||
|
||||
### Edítalo { #edit-it }
|
||||
|
||||
@@ -78,7 +78,7 @@ Eso es todo.
|
||||
|
||||
Esas son las "anotaciones de tipos":
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
|
||||
|
||||
Eso no es lo mismo que declarar valores predeterminados como sería con:
|
||||
|
||||
@@ -106,7 +106,7 @@ Con eso, puedes desplazarte, viendo las opciones, hasta que encuentres la que "t
|
||||
|
||||
Revisa esta función, ya tiene anotaciones de tipos:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
|
||||
|
||||
Porque el editor conoce los tipos de las variables, no solo obtienes autocompletado, también obtienes chequeo de errores:
|
||||
|
||||
@@ -114,7 +114,7 @@ Porque el editor conoce los tipos de las variables, no solo obtienes autocomplet
|
||||
|
||||
Ahora sabes que debes corregirlo, convertir `age` a un string con `str(age)`:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
|
||||
{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
|
||||
|
||||
## Declaración de tipos { #declaring-types }
|
||||
|
||||
@@ -133,29 +133,32 @@ Puedes usar, por ejemplo:
|
||||
* `bool`
|
||||
* `bytes`
|
||||
|
||||
{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
|
||||
|
||||
### Tipos genéricos con parámetros de tipo { #generic-types-with-type-parameters }
|
||||
### Módulo `typing` { #typing-module }
|
||||
|
||||
Hay algunas estructuras de datos que pueden contener otros valores, como `dict`, `list`, `set` y `tuple`. Y los valores internos también pueden tener su propio tipo.
|
||||
Para algunos casos adicionales, podrías necesitar importar algunas cosas del módulo `typing` de la standard library, por ejemplo cuando quieres declarar que algo tiene "cualquier tipo", puedes usar `Any` de `typing`:
|
||||
|
||||
Estos tipos que tienen tipos internos se denominan tipos "**genéricos**". Y es posible declararlos, incluso con sus tipos internos.
|
||||
```python
|
||||
from typing import Any
|
||||
|
||||
Para declarar esos tipos y los tipos internos, puedes usar el módulo estándar de Python `typing`. Existe específicamente para soportar estas anotaciones de tipos.
|
||||
|
||||
#### Versiones más recientes de Python { #newer-versions-of-python }
|
||||
def some_function(data: Any):
|
||||
print(data)
|
||||
```
|
||||
|
||||
La sintaxis que utiliza `typing` es **compatible** con todas las versiones, desde Python 3.6 hasta las versiones más recientes, incluyendo Python 3.9, Python 3.10, etc.
|
||||
### Tipos genéricos { #generic-types }
|
||||
|
||||
A medida que avanza Python, las **versiones más recientes** vienen con soporte mejorado para estas anotaciones de tipos y en muchos casos ni siquiera necesitarás importar y usar el módulo `typing` para declarar las anotaciones de tipos.
|
||||
Algunos tipos pueden tomar "parámetros de tipo" entre corchetes, para definir sus tipos internos, por ejemplo una "lista de strings" se declararía `list[str]`.
|
||||
|
||||
Si puedes elegir una versión más reciente de Python para tu proyecto, podrás aprovechar esa simplicidad adicional.
|
||||
Estos tipos que pueden tomar parámetros de tipo se llaman **Tipos Genéricos** o **Genéricos**.
|
||||
|
||||
En toda la documentación hay ejemplos compatibles con cada versión de Python (cuando hay una diferencia).
|
||||
Puedes usar los mismos tipos integrados como genéricos (con corchetes y tipos dentro):
|
||||
|
||||
Por ejemplo, "**Python 3.6+**" significa que es compatible con Python 3.6 o superior (incluyendo 3.7, 3.8, 3.9, 3.10, etc). Y "**Python 3.9+**" significa que es compatible con Python 3.9 o superior (incluyendo 3.10, etc).
|
||||
|
||||
Si puedes usar las **últimas versiones de Python**, utiliza los ejemplos para la última versión, esos tendrán la **mejor y más simple sintaxis**, por ejemplo, "**Python 3.10+**".
|
||||
* `list`
|
||||
* `tuple`
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
#### Lista { #list }
|
||||
|
||||
@@ -167,7 +170,7 @@ Como tipo, pon `list`.
|
||||
|
||||
Como la lista es un tipo que contiene algunos tipos internos, los pones entre corchetes:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
|
||||
|
||||
/// info | Información
|
||||
|
||||
@@ -193,7 +196,7 @@ Y aún así, el editor sabe que es un `str` y proporciona soporte para eso.
|
||||
|
||||
Harías lo mismo para declarar `tuple`s y `set`s:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
|
||||
|
||||
Esto significa:
|
||||
|
||||
@@ -208,7 +211,7 @@ El primer parámetro de tipo es para las claves del `dict`.
|
||||
|
||||
El segundo parámetro de tipo es para los valores del `dict`:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
|
||||
|
||||
Esto significa:
|
||||
|
||||
@@ -218,46 +221,22 @@ Esto significa:
|
||||
|
||||
#### Union { #union }
|
||||
|
||||
Puedes declarar que una variable puede ser cualquier de **varios tipos**, por ejemplo, un `int` o un `str`.
|
||||
Puedes declarar que una variable puede ser cualquiera de **varios tipos**, por ejemplo, un `int` o un `str`.
|
||||
|
||||
En Python 3.6 y posterior (incluyendo Python 3.10) puedes usar el tipo `Union` de `typing` y poner dentro de los corchetes los posibles tipos a aceptar.
|
||||
Para definirlo usas la <dfn title='también llamado "operador OR a nivel de bits", pero ese significado no es relevante aquí'>barra vertical (`|`)</dfn> para separar ambos tipos.
|
||||
|
||||
En Python 3.10 también hay una **nueva sintaxis** donde puedes poner los posibles tipos separados por una <abbr title='también llamado "operador OR a nivel de bits", pero ese significado no es relevante aquí'>barra vertical (`|`)</abbr>.
|
||||
|
||||
//// tab | Python 3.10+
|
||||
Esto se llama una "unión", porque la variable puede ser cualquiera en la unión de esos dos conjuntos de tipos.
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!> ../../docs_src/python_types/tutorial008b_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
En ambos casos, esto significa que `item` podría ser un `int` o un `str`.
|
||||
Esto significa que `item` podría ser un `int` o un `str`.
|
||||
|
||||
#### Posiblemente `None` { #possibly-none }
|
||||
|
||||
Puedes declarar que un valor podría tener un tipo, como `str`, pero que también podría ser `None`.
|
||||
|
||||
En Python 3.6 y posteriores (incluyendo Python 3.10) puedes declararlo importando y usando `Optional` del módulo `typing`.
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!../../docs_src/python_types/tutorial009_py39.py!}
|
||||
```
|
||||
|
||||
Usar `Optional[str]` en lugar de solo `str` te permitirá al editor ayudarte a detectar errores donde podrías estar asumiendo que un valor siempre es un `str`, cuando en realidad también podría ser `None`.
|
||||
|
||||
`Optional[Something]` es realmente un atajo para `Union[Something, None]`, son equivalentes.
|
||||
|
||||
Esto también significa que en Python 3.10, puedes usar `Something | None`:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="1"
|
||||
@@ -266,96 +245,7 @@ Esto también significa que en Python 3.10, puedes usar `Something | None`:
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!> ../../docs_src/python_types/tutorial009_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ alternativa
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!> ../../docs_src/python_types/tutorial009b_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
#### Uso de `Union` u `Optional` { #using-union-or-optional }
|
||||
|
||||
Si estás usando una versión de Python inferior a 3.10, aquí tienes un consejo desde mi punto de vista muy **subjetivo**:
|
||||
|
||||
* 🚨 Evita usar `Optional[SomeType]`
|
||||
* En su lugar ✨ **usa `Union[SomeType, None]`** ✨.
|
||||
|
||||
Ambos son equivalentes y debajo son lo mismo, pero recomendaría `Union` en lugar de `Optional` porque la palabra "**opcional**" parecería implicar que el valor es opcional, y en realidad significa "puede ser `None`", incluso si no es opcional y aún es requerido.
|
||||
|
||||
Creo que `Union[SomeType, None]` es más explícito sobre lo que significa.
|
||||
|
||||
Se trata solo de las palabras y nombres. Pero esas palabras pueden afectar cómo tú y tus compañeros de equipo piensan sobre el código.
|
||||
|
||||
Como ejemplo, tomemos esta función:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
|
||||
|
||||
El parámetro `name` está definido como `Optional[str]`, pero **no es opcional**, no puedes llamar a la función sin el parámetro:
|
||||
|
||||
```Python
|
||||
say_hi() # ¡Oh, no, esto lanza un error! 😱
|
||||
```
|
||||
|
||||
El parámetro `name` sigue siendo **requerido** (no *opcional*) porque no tiene un valor predeterminado. Aún así, `name` acepta `None` como valor:
|
||||
|
||||
```Python
|
||||
say_hi(name=None) # Esto funciona, None es válido 🎉
|
||||
```
|
||||
|
||||
La buena noticia es que, una vez que estés en Python 3.10, no tendrás que preocuparte por eso, ya que podrás simplemente usar `|` para definir uniones de tipos:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
|
||||
|
||||
Y entonces no tendrás que preocuparte por nombres como `Optional` y `Union`. 😎
|
||||
|
||||
#### Tipos genéricos { #generic-types }
|
||||
|
||||
Estos tipos que toman parámetros de tipo en corchetes se llaman **Tipos Genéricos** o **Genéricos**, por ejemplo:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
Puedes usar los mismos tipos integrados como genéricos (con corchetes y tipos dentro):
|
||||
|
||||
* `list`
|
||||
* `tuple`
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
Y, como con versiones anteriores de Python, desde el módulo `typing`:
|
||||
|
||||
* `Union`
|
||||
* `Optional`
|
||||
* ...y otros.
|
||||
|
||||
En Python 3.10, como alternativa a usar los genéricos `Union` y `Optional`, puedes usar la <abbr title='también llamado "operador OR a nivel de bits", pero ese significado no es relevante aquí'>barra vertical (`|`)</abbr> para declarar uniones de tipos, eso es mucho mejor y más simple.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
Puedes usar los mismos tipos integrados como genéricos (con corchetes y tipos dentro):
|
||||
|
||||
* `list`
|
||||
* `tuple`
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
Y generics desde el módulo `typing`:
|
||||
|
||||
* `Union`
|
||||
* `Optional`
|
||||
* ...y otros.
|
||||
|
||||
////
|
||||
Usar `str | None` en lugar de solo `str` te permitirá al editor ayudarte a detectar errores donde podrías estar asumiendo que un valor siempre es un `str`, cuando en realidad también podría ser `None`.
|
||||
|
||||
### Clases como tipos { #classes-as-types }
|
||||
|
||||
@@ -363,11 +253,11 @@ También puedes declarar una clase como el tipo de una variable.
|
||||
|
||||
Digamos que tienes una clase `Person`, con un nombre:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
|
||||
{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
|
||||
|
||||
Luego puedes declarar una variable para que sea de tipo `Person`:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
|
||||
{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
|
||||
|
||||
Y luego, nuevamente, obtienes todo el soporte del editor:
|
||||
|
||||
@@ -403,19 +293,13 @@ Para saber más sobre <a href="https://docs.pydantic.dev/" class="external-link"
|
||||
|
||||
Verás mucho más de todo esto en práctica en el [Tutorial - Guía del Usuario](tutorial/index.md){.internal-link target=_blank}.
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
Pydantic tiene un comportamiento especial cuando utilizas `Optional` o `Union[Something, None]` sin un valor por defecto, puedes leer más sobre ello en la documentación de Pydantic sobre <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">Required Optional fields</a>.
|
||||
|
||||
///
|
||||
|
||||
## Anotaciones de tipos con metadata { #type-hints-with-metadata-annotations }
|
||||
|
||||
Python también tiene una funcionalidad que permite poner **<abbr title="Datos sobre los datos, en este caso, información sobre el tipo, por ejemplo, una descripción.">metadatos</abbr> adicional** en estas anotaciones de tipos usando `Annotated`.
|
||||
Python también tiene una funcionalidad que permite poner **<dfn title="Datos sobre los datos, en este caso, información sobre el tipo, por ejemplo, una descripción.">metadata</dfn> adicional** en estas anotaciones de tipos usando `Annotated`.
|
||||
|
||||
Desde Python 3.9, `Annotated` es parte de la standard library, así que puedes importarlo desde `typing`.
|
||||
Puedes importar `Annotated` desde `typing`.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
|
||||
{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
|
||||
|
||||
Python en sí no hace nada con este `Annotated`. Y para los editores y otras herramientas, el tipo sigue siendo `str`.
|
||||
|
||||
|
||||
11
docs/es/docs/translation-banner.md
Normal file
11
docs/es/docs/translation-banner.md
Normal file
@@ -0,0 +1,11 @@
|
||||
/// details | 🌐 Traducción por IA y humanos
|
||||
|
||||
Esta traducción fue hecha por IA guiada por humanos. 🤝
|
||||
|
||||
Podría tener errores al interpretar el significado original, o sonar poco natural, etc. 🤖
|
||||
|
||||
Puedes mejorar esta traducción [ayudándonos a guiar mejor al LLM de IA](https://fastapi.tiangolo.com/es/contributing/#translations).
|
||||
|
||||
[Versión en inglés](ENGLISH_VERSION_URL)
|
||||
|
||||
///
|
||||
@@ -15,7 +15,7 @@ Esto incluye, por ejemplo:
|
||||
|
||||
Primero, importa `BackgroundTasks` y define un parámetro en tu *path operation function* con una declaración de tipo de `BackgroundTasks`:
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
|
||||
|
||||
**FastAPI** creará el objeto de tipo `BackgroundTasks` por ti y lo pasará como ese parámetro.
|
||||
|
||||
@@ -31,13 +31,13 @@ En este caso, la función de tarea escribirá en un archivo (simulando el envío
|
||||
|
||||
Y como la operación de escritura no usa `async` y `await`, definimos la función con un `def` normal:
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
|
||||
|
||||
## Agregar la tarea en segundo plano { #add-the-background-task }
|
||||
|
||||
Dentro de tu *path operation function*, pasa tu función de tarea al objeto de *background tasks* con el método `.add_task()`:
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
|
||||
|
||||
`.add_task()` recibe como argumentos:
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ Puedes crear las *path operations* para ese módulo usando `APIRouter`.
|
||||
|
||||
Lo importas y creas una "instance" de la misma manera que lo harías con la clase `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
|
||||
|
||||
### *Path operations* con `APIRouter` { #path-operations-with-apirouter }
|
||||
|
||||
@@ -93,7 +93,7 @@ Y luego lo usas para declarar tus *path operations*.
|
||||
|
||||
Úsalo de la misma manera que usarías la clase `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
|
||||
|
||||
Puedes pensar en `APIRouter` como una clase "mini `FastAPI`".
|
||||
|
||||
@@ -117,7 +117,7 @@ Así que las ponemos en su propio módulo `dependencies` (`app/dependencies.py`)
|
||||
|
||||
Ahora utilizaremos una dependencia simple para leer un header `X-Token` personalizado:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -149,7 +149,7 @@ Sabemos que todas las *path operations* en este módulo tienen el mismo:
|
||||
|
||||
Entonces, en lugar de agregar todo eso a cada *path operation*, podemos agregarlo al `APIRouter`.
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
|
||||
|
||||
Como el path de cada *path operation* tiene que empezar con `/`, como en:
|
||||
|
||||
@@ -208,7 +208,7 @@ Y necesitamos obtener la función de dependencia del módulo `app.dependencies`,
|
||||
|
||||
Así que usamos un import relativo con `..` para las dependencias:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
|
||||
|
||||
#### Cómo funcionan los imports relativos { #how-relative-imports-work }
|
||||
|
||||
@@ -279,7 +279,7 @@ No estamos agregando el prefijo `/items` ni los `tags=["items"]` a cada *path op
|
||||
|
||||
Pero aún podemos agregar _más_ `tags` que se aplicarán a una *path operation* específica, y también algunas `responses` extra específicas para esa *path operation*:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -305,13 +305,13 @@ Importas y creas una clase `FastAPI` como normalmente.
|
||||
|
||||
Y podemos incluso declarar [dependencias globales](dependencies/global-dependencies.md){.internal-link target=_blank} que se combinarán con las dependencias para cada `APIRouter`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
|
||||
|
||||
### Importar el `APIRouter` { #import-the-apirouter }
|
||||
|
||||
Ahora importamos los otros submódulos que tienen `APIRouter`s:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
|
||||
|
||||
Como los archivos `app/routers/users.py` y `app/routers/items.py` son submódulos que son parte del mismo paquete de Python `app`, podemos usar un solo punto `.` para importarlos usando "imports relativos".
|
||||
|
||||
@@ -374,13 +374,13 @@ el `router` de `users` sobrescribiría el de `items` y no podríamos usarlos al
|
||||
|
||||
Así que, para poder usar ambos en el mismo archivo, importamos los submódulos directamente:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
|
||||
|
||||
### Incluir los `APIRouter`s para `users` y `items` { #include-the-apirouters-for-users-and-items }
|
||||
|
||||
Ahora, incluyamos los `router`s de los submódulos `users` y `items`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
|
||||
|
||||
/// info | Información
|
||||
|
||||
@@ -420,13 +420,13 @@ Contiene un `APIRouter` con algunas *path operations* de administración que tu
|
||||
|
||||
Para este ejemplo será súper simple. Pero digamos que porque está compartido con otros proyectos en la organización, no podemos modificarlo y agregar un `prefix`, `dependencies`, `tags`, etc. directamente al `APIRouter`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
|
||||
|
||||
Pero aún queremos configurar un `prefix` personalizado al incluir el `APIRouter` para que todas sus *path operations* comiencen con `/admin`, queremos asegurarlo con las `dependencies` que ya tenemos para este proyecto, y queremos incluir `tags` y `responses`.
|
||||
|
||||
Podemos declarar todo eso sin tener que modificar el `APIRouter` original pasando esos parámetros a `app.include_router()`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
|
||||
|
||||
De esa manera, el `APIRouter` original permanecerá sin modificar, por lo que aún podemos compartir ese mismo archivo `app/internal/admin.py` con otros proyectos en la organización.
|
||||
|
||||
@@ -447,7 +447,7 @@ También podemos agregar *path operations* directamente a la app de `FastAPI`.
|
||||
|
||||
Aquí lo hacemos... solo para mostrar que podemos 🤷:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *}
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
|
||||
|
||||
y funcionará correctamente, junto con todas las otras *path operations* añadidas con `app.include_router()`.
|
||||
|
||||
|
||||
@@ -104,12 +104,6 @@ Como, por defecto, los valores singulares se interpretan como parámetros de que
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
O en Python 3.9:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Por ejemplo:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
|
||||
|
||||
@@ -164,7 +164,7 @@ images: list[Image]
|
||||
|
||||
como en:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
|
||||
|
||||
## Soporte de editor en todas partes { #editor-support-everywhere }
|
||||
|
||||
@@ -194,7 +194,7 @@ Eso es lo que vamos a ver aquí.
|
||||
|
||||
En este caso, aceptarías cualquier `dict` siempre que tenga claves `int` con valores `float`:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ Con solo esa declaración de tipo en Python, **FastAPI** hará lo siguiente:
|
||||
* Proporcionar los datos recibidos en el parámetro `item`.
|
||||
* Como lo declaraste en la función como de tipo `Item`, también tendrás todo el soporte del editor (autocompletado, etc.) para todos los atributos y sus tipos.
|
||||
* Generar definiciones de <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> para tu modelo, que también puedes usar en cualquier otro lugar si tiene sentido para tu proyecto.
|
||||
* Esos esquemas serán parte del esquema de OpenAPI generado y usados por las <abbr title="User Interfaces – Interfaces de usuario">UIs</abbr> de documentación automática.
|
||||
* Esos esquemas serán parte del esquema de OpenAPI generado y usados por las <abbr title="User Interfaces - Interfaces de usuario">UIs</abbr> de documentación automática.
|
||||
|
||||
## Documentación automática { #automatic-docs }
|
||||
|
||||
@@ -155,7 +155,7 @@ Los parámetros de la función se reconocerán de la siguiente manera:
|
||||
|
||||
FastAPI sabrá que el valor de `q` no es requerido debido al valor por defecto `= None`.
|
||||
|
||||
El `str | None` (Python 3.10+) o `Union` en `Union[str, None]` (Python 3.9+) no es utilizado por FastAPI para determinar que el valor no es requerido, sabrá que no es requerido porque tiene un valor por defecto de `= None`.
|
||||
El `str | None` no es utilizado por FastAPI para determinar que el valor no es requerido, sabrá que no es requerido porque tiene un valor por defecto de `= None`.
|
||||
|
||||
Pero agregar las anotaciones de tipos permitirá que tu editor te brinde un mejor soporte y detecte errores.
|
||||
|
||||
@@ -163,4 +163,4 @@ Pero agregar las anotaciones de tipos permitirá que tu editor te brinde un mejo
|
||||
|
||||
## Sin Pydantic { #without-pydantic }
|
||||
|
||||
Si no quieres usar modelos de Pydantic, también puedes usar parámetros **Body**. Consulta la documentación para [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
Si no quieres usar modelos de Pydantic, también puedes usar parámetros **Body**. Consulta la documentación para [Body - Múltiples parámetros: Valores singulares en el body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
|
||||
@@ -46,7 +46,7 @@ Pero incluso si **rellenas los datos** y haces clic en "Execute", como la UI de
|
||||
|
||||
En algunos casos de uso especiales (probablemente no muy comunes), podrías querer **restringir** las cookies que deseas recibir.
|
||||
|
||||
Tu API ahora tiene el poder de controlar su propio <abbr title="Esto es una broma, por si acaso. No tiene nada que ver con los consentimientos de cookies, pero es gracioso que incluso la API ahora pueda rechazar las pobres cookies. Toma una cookie. 🍪">consentimiento de cookies</abbr>. 🤪🍪
|
||||
Tu API ahora tiene el poder de controlar su propio <dfn title="Esto es una broma, por si acaso. No tiene nada que ver con los consentimientos de cookies, pero es gracioso que incluso la API ahora pueda rechazar las pobres cookies. Toma una cookie. 🍪">consentimiento de cookies</dfn>. 🤪🍪
|
||||
|
||||
Puedes usar la configuración del modelo de Pydantic para `prohibir` cualquier campo `extra`:
|
||||
|
||||
@@ -54,9 +54,9 @@ Puedes usar la configuración del modelo de Pydantic para `prohibir` cualquier c
|
||||
|
||||
Si un cliente intenta enviar algunas **cookies extra**, recibirán un response de **error**.
|
||||
|
||||
Pobres banners de cookies con todo su esfuerzo para obtener tu consentimiento para que la <abbr title="Esta es otra broma. No me prestes atención. Toma un café para tu cookie. ☕">API lo rechace</abbr>. 🍪
|
||||
Pobres banners de cookies con todo su esfuerzo para obtener tu consentimiento para que la <dfn title="Esta es otra broma. No me prestes atención. Toma un café para tu cookie. ☕">API lo rechace</dfn>. 🍪
|
||||
|
||||
Por ejemplo, si el cliente intenta enviar una cookie `santa_tracker` con un valor de `good-list-please`, el cliente recibirá un response de **error** que le informa que la cookie `santa_tracker` <abbr title="Santa desaprueba la falta de cookies. 🎅 Está bien, no más bromas de cookies.">no está permitida</abbr>:
|
||||
Por ejemplo, si el cliente intenta enviar una cookie `santa_tracker` con un valor de `good-list-please`, el cliente recibirá un response de **error** que le informa que la `santa_tracker` <dfn title="Santa desaprueba la falta de cookies. 🎅 Está bien, no más bromas de cookies.">cookie no está permitida</dfn>:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -73,4 +73,4 @@ Por ejemplo, si el cliente intenta enviar una cookie `santa_tracker` con un valo
|
||||
|
||||
## Resumen { #summary }
|
||||
|
||||
Puedes usar **modelos de Pydantic** para declarar <abbr title="Toma una última cookie antes de irte. 🍪">**cookies**</abbr> en **FastAPI**. 😎
|
||||
Puedes usar **modelos de Pydantic** para declarar <dfn title="Toma una última cookie antes de irte. 🍪">**cookies**</dfn> en **FastAPI**. 😎
|
||||
|
||||
@@ -46,7 +46,8 @@ También puedes especificar si tu backend permite:
|
||||
* Métodos HTTP específicos (`POST`, `PUT`) o todos ellos con el comodín `"*"`.
|
||||
* Headers HTTP específicos o todos ellos con el comodín `"*"`.
|
||||
|
||||
{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
|
||||
{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
|
||||
|
||||
|
||||
Los parámetros predeterminados utilizados por la implementación de `CORSMiddleware` son restrictivos por defecto, por lo que necesitarás habilitar explícitamente orígenes, métodos o headers particulares para que los navegadores estén permitidos de usarlos en un contexto de Cross-Domain.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Puedes conectar el depurador en tu editor, por ejemplo con Visual Studio Code o
|
||||
|
||||
En tu aplicación de FastAPI, importa y ejecuta `uvicorn` directamente:
|
||||
|
||||
{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
|
||||
{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
|
||||
|
||||
### Acerca de `__name__ == "__main__"` { #about-name-main }
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ Ahora puedes declarar tu dependencia usando esta clase.
|
||||
|
||||
Nota cómo escribimos `CommonQueryParams` dos veces en el código anterior:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
@@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ sin `Annotated`
|
||||
//// tab | Python 3.10+ sin `Annotated`
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -137,7 +137,7 @@ Es a partir de este que **FastAPI** extraerá los parámetros declarados y es lo
|
||||
|
||||
En este caso, el primer `CommonQueryParams`, en:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, ...
|
||||
@@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ...
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ sin `Annotated`
|
||||
//// tab | Python 3.10+ sin `Annotated`
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -163,7 +163,7 @@ commons: CommonQueryParams ...
|
||||
|
||||
De hecho, podrías escribir simplemente:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[Any, Depends(CommonQueryParams)]
|
||||
@@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)]
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ sin `Annotated`
|
||||
//// tab | Python 3.10+ sin `Annotated`
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -197,7 +197,7 @@ Pero declarar el tipo es recomendable, ya que de esa manera tu editor sabrá lo
|
||||
|
||||
Pero ves que estamos teniendo algo de repetición de código aquí, escribiendo `CommonQueryParams` dos veces:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
@@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ sin `Annotated`
|
||||
//// tab | Python 3.10+ sin `Annotated`
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -225,7 +225,7 @@ Para esos casos específicos, puedes hacer lo siguiente:
|
||||
|
||||
En lugar de escribir:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
@@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ sin `Annotated`
|
||||
//// tab | Python 3.10+ sin `Annotated`
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
|
||||
...escribes:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends()]
|
||||
@@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()]
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ sin `Annotated`
|
||||
//// tab | Python 3.10+ sin `Annotated`
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ El decorador de *path operation* recibe un argumento opcional `dependencies`.
|
||||
|
||||
Debe ser una `list` de `Depends()`:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
|
||||
|
||||
Estas dependencias serán ejecutadas/resueltas de la misma manera que las dependencias normales. Pero su valor (si devuelven alguno) no será pasado a tu *path operation function*.
|
||||
|
||||
@@ -44,13 +44,13 @@ Puedes usar las mismas *funciones* de dependencia que usas normalmente.
|
||||
|
||||
Pueden declarar requisitos de request (como headers) u otras sub-dependencias:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
|
||||
|
||||
### Lanzar excepciones { #raise-exceptions }
|
||||
|
||||
Estas dependencias pueden `raise` excepciones, igual que las dependencias normales:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
|
||||
|
||||
### Valores de retorno { #return-values }
|
||||
|
||||
@@ -58,7 +58,7 @@ Y pueden devolver valores o no, los valores no serán usados.
|
||||
|
||||
Así que, puedes reutilizar una dependencia normal (que devuelve un valor) que ya uses en otro lugar, y aunque el valor no se use, la dependencia será ejecutada:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
|
||||
|
||||
## Dependencias para un grupo de *path operations* { #dependencies-for-a-group-of-path-operations }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dependencias con yield { #dependencies-with-yield }
|
||||
|
||||
FastAPI admite dependencias que realizan algunos <abbr title='a veces también llamado "código de salida", "código de limpieza", "código de teardown", "código de cierre", "código de salida del context manager", etc.'>pasos adicionales después de finalizar</abbr>.
|
||||
FastAPI admite dependencias que realizan algunos <dfn title='a veces también llamado "código de salida", "código de limpieza", "código de teardown", "código de cierre", "código de salida del context manager", etc.'>pasos adicionales después de finalizar</dfn>.
|
||||
|
||||
Para hacer esto, usa `yield` en lugar de `return`, y escribe los pasos adicionales (código) después.
|
||||
|
||||
@@ -29,15 +29,15 @@ Por ejemplo, podrías usar esto para crear una sesión de base de datos y cerrar
|
||||
|
||||
Solo el código anterior e incluyendo la declaración `yield` se ejecuta antes de crear un response:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *}
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}
|
||||
|
||||
El valor generado es lo que se inyecta en *path operations* y otras dependencias:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *}
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}
|
||||
|
||||
El código posterior a la declaración `yield` se ejecuta después del response:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *}
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -57,7 +57,7 @@ Por lo tanto, puedes buscar esa excepción específica dentro de la dependencia
|
||||
|
||||
Del mismo modo, puedes usar `finally` para asegurarte de que los pasos de salida se ejecuten, sin importar si hubo una excepción o no.
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *}
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}
|
||||
|
||||
## Sub-dependencias con `yield` { #sub-dependencies-with-yield }
|
||||
|
||||
@@ -67,7 +67,7 @@ Puedes tener sub-dependencias y "árboles" de sub-dependencias de cualquier tama
|
||||
|
||||
Por ejemplo, `dependency_c` puede tener una dependencia de `dependency_b`, y `dependency_b` de `dependency_a`:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}
|
||||
|
||||
Y todas ellas pueden usar `yield`.
|
||||
|
||||
@@ -75,7 +75,7 @@ En este caso, `dependency_c`, para ejecutar su código de salida, necesita que e
|
||||
|
||||
Y, a su vez, `dependency_b` necesita que el valor de `dependency_a` (aquí llamado `dep_a`) esté disponible para su código de salida.
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}
|
||||
|
||||
De la misma manera, podrías tener algunas dependencias con `yield` y otras dependencias con `return`, y hacer que algunas de esas dependan de algunas de las otras.
|
||||
|
||||
@@ -109,7 +109,7 @@ Pero está ahí para ti si la necesitas. 🤓
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
|
||||
{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}
|
||||
|
||||
Si quieres capturar excepciones y crear un response personalizado en base a eso, crea un [Manejador de Excepciones Personalizado](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
|
||||
|
||||
@@ -117,7 +117,7 @@ Si quieres capturar excepciones y crear un response personalizado en base a eso,
|
||||
|
||||
Si capturas una excepción usando `except` en una dependencia con `yield` y no la lanzas nuevamente (o lanzas una nueva excepción), FastAPI no podrá notar que hubo una excepción, al igual que sucedería con Python normal:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
|
||||
{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
|
||||
|
||||
En este caso, el cliente verá un response *HTTP 500 Internal Server Error* como debería, dado que no estamos lanzando una `HTTPException` o similar, pero el servidor **no tendrá ningún registro** ni ninguna otra indicación de cuál fue el error. 😱
|
||||
|
||||
@@ -127,7 +127,7 @@ Si capturas una excepción en una dependencia con `yield`, a menos que estés la
|
||||
|
||||
Puedes volver a lanzar la misma excepción usando `raise`:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
|
||||
{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}
|
||||
|
||||
Ahora el cliente obtendrá el mismo response *HTTP 500 Internal Server Error*, pero el servidor tendrá nuestro `InternalError` personalizado en los registros. 😎
|
||||
|
||||
@@ -190,7 +190,7 @@ Normalmente, el código de salida de las dependencias con `yield` se ejecuta **d
|
||||
|
||||
Pero si sabes que no necesitarás usar la dependencia después de regresar de la *path operation function*, puedes usar `Depends(scope="function")` para decirle a FastAPI que debe cerrar la dependencia después de que la *path operation function* regrese, pero **antes** de que se envíe el **response**.
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
|
||||
{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}
|
||||
|
||||
`Depends()` recibe un parámetro `scope` que puede ser:
|
||||
|
||||
@@ -234,7 +234,6 @@ participant operation as Path Operation
|
||||
Las dependencias con `yield` han evolucionado con el tiempo para cubrir diferentes casos de uso y corregir algunos problemas.
|
||||
|
||||
Si quieres ver qué ha cambiado en diferentes versiones de FastAPI, puedes leer más al respecto en la guía avanzada, en [Dependencias avanzadas - Dependencias con `yield`, `HTTPException`, `except` y Tareas en Background](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}.
|
||||
|
||||
## Context Managers { #context-managers }
|
||||
|
||||
### Qué son los "Context Managers" { #what-are-context-managers }
|
||||
@@ -270,7 +269,7 @@ En Python, puedes crear Context Managers <a href="https://docs.python.org/3/refe
|
||||
También puedes usarlos dentro de las dependencias de **FastAPI** con `yield` usando
|
||||
`with` o `async with` en la función de dependencia:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial010_py39.py hl[1:9,13] *}
|
||||
{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Similar a como puedes [agregar `dependencies` a los *path operation decorators*]
|
||||
|
||||
En ese caso, se aplicarán a todas las *path operations* en la aplicación:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[17] *}
|
||||
{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}
|
||||
|
||||
Y todas las ideas en la sección sobre [agregar `dependencies` a los *path operation decorators*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} siguen aplicándose, pero en este caso, a todas las *path operations* en la app.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dependencias { #dependencies }
|
||||
|
||||
**FastAPI** tiene un sistema de **<abbr title="también conocido como componentes, recursos, proveedores, servicios, inyectables">Inyección de Dependencias</abbr>** muy poderoso pero intuitivo.
|
||||
**FastAPI** tiene un sistema de **<dfn title="también conocido como componentes, recursos, proveedores, servicios, inyectables">Inyección de Dependencias</dfn>** muy poderoso pero intuitivo.
|
||||
|
||||
Está diseñado para ser muy simple de usar, y para hacer que cualquier desarrollador integre otros componentes con **FastAPI** de forma muy sencilla.
|
||||
|
||||
|
||||
@@ -58,11 +58,11 @@ query_extractor --> query_or_cookie_extractor --> read_query
|
||||
|
||||
Si una de tus dependencias se declara varias veces para la misma *path operation*, por ejemplo, múltiples dependencias tienen una sub-dependencia común, **FastAPI** sabrá llamar a esa sub-dependencia solo una vez por request.
|
||||
|
||||
Y guardará el valor devuelto en un <abbr title="Una utilidad/sistema para almacenar valores calculados/generados, para reutilizarlos en lugar de calcularlos nuevamente.">"cache"</abbr> y lo pasará a todos los "dependants" que lo necesiten en ese request específico, en lugar de llamar a la dependencia varias veces para el mismo request.
|
||||
Y guardará el valor devuelto en un <dfn title="Una utilidad/sistema para almacenar valores calculados/generados, para reutilizarlos en lugar de calcularlos nuevamente.">"caché"</dfn> y lo pasará a todos los "dependants" que lo necesiten en ese request específico, en lugar de llamar a la dependencia varias veces para el mismo request.
|
||||
|
||||
En un escenario avanzado donde sabes que necesitas que la dependencia se llame en cada paso (posiblemente varias veces) en el mismo request en lugar de usar el valor "cache", puedes establecer el parámetro `use_cache=False` al usar `Depends`:
|
||||
En un escenario avanzado donde sabes que necesitas que la dependencia se llame en cada paso (posiblemente varias veces) en el mismo request en lugar de usar el valor "en caché", puedes establecer el parámetro `use_cache=False` al usar `Depends`:
|
||||
|
||||
//// tab | Python 3.9+
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
|
||||
@@ -71,7 +71,7 @@ async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_ca
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ sin Anotaciones
|
||||
//// tab | Python 3.10+ sin Anotaciones
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ En este ejemplo, convertiría el modelo de Pydantic a un `dict`, y el `datetime`
|
||||
|
||||
El resultado de llamarlo es algo que puede ser codificado con la función estándar de Python <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a>.
|
||||
|
||||
No devuelve un gran `str` que contenga los datos en formato JSON (como una cadena de texto). Devuelve una estructura de datos estándar de Python (por ejemplo, un `dict`) con valores y sub-valores que son todos compatibles con JSON.
|
||||
No devuelve un gran `str` que contenga los datos en formato JSON (como un string). Devuelve una estructura de datos estándar de Python (por ejemplo, un `dict`) con valores y sub-valores que son todos compatibles con JSON.
|
||||
|
||||
/// note | Nota
|
||||
|
||||
|
||||
@@ -190,9 +190,9 @@ Pero si ponemos eso en la asignación `response_model=PlaneItem | CarItem` obten
|
||||
|
||||
De la misma manera, puedes declarar responses de listas de objetos.
|
||||
|
||||
Para eso, usa el `typing.List` estándar de Python (o simplemente `list` en Python 3.9 y posteriores):
|
||||
Para eso, usa la `list` estándar de Python:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
|
||||
{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
|
||||
|
||||
## Response con `dict` arbitrario { #response-with-arbitrary-dict }
|
||||
|
||||
@@ -200,9 +200,9 @@ También puedes declarar un response usando un `dict` arbitrario plano, declaran
|
||||
|
||||
Esto es útil si no conoces los nombres de los campos/atributos válidos (que serían necesarios para un modelo Pydantic) de antemano.
|
||||
|
||||
En este caso, puedes usar `typing.Dict` (o solo `dict` en Python 3.9 y posteriores):
|
||||
En este caso, puedes usar `dict`:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
|
||||
{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
|
||||
|
||||
## Recapitulación { #recap }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
El archivo FastAPI más simple podría verse así:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py *}
|
||||
|
||||
Copia eso en un archivo `main.py`.
|
||||
|
||||
@@ -56,7 +56,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
|
||||
Esa línea muestra la URL donde tu aplicación está siendo servida, en tu máquina local.
|
||||
|
||||
### Compruébalo { #check-it }
|
||||
### Revisa { #check-it }
|
||||
|
||||
Abre tu navegador en <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
|
||||
|
||||
@@ -183,7 +183,7 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
### Paso 1: importa `FastAPI` { #step-1-import-fastapi }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
|
||||
|
||||
`FastAPI` es una clase de Python que proporciona toda la funcionalidad para tu API.
|
||||
|
||||
@@ -197,7 +197,7 @@ Puedes usar toda la funcionalidad de <a href="https://www.starlette.dev/" class=
|
||||
|
||||
### Paso 2: crea una "instance" de `FastAPI` { #step-2-create-a-fastapi-instance }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}
|
||||
|
||||
Aquí la variable `app` será una "instance" de la clase `FastAPI`.
|
||||
|
||||
@@ -266,12 +266,12 @@ Vamos a llamarlas "**operaciones**" también.
|
||||
|
||||
#### Define un *path operation decorator* { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
|
||||
|
||||
El `@app.get("/")` le dice a **FastAPI** que la función justo debajo se encarga de manejar requests que vayan a:
|
||||
|
||||
* el path `/`
|
||||
* usando una <abbr title="un método HTTP GET"><code>get</code> operation</abbr>
|
||||
* usando una <dfn title="un método HTTP GET"><code>get</code> operación</dfn>
|
||||
|
||||
/// info | Información sobre `@decorator`
|
||||
|
||||
@@ -320,7 +320,7 @@ Esta es nuestra "**path operation function**":
|
||||
* **operation**: es `get`.
|
||||
* **function**: es la función debajo del "decorador" (debajo de `@app.get("/")`).
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}
|
||||
|
||||
Esta es una función de Python.
|
||||
|
||||
@@ -332,7 +332,7 @@ En este caso, es una función `async`.
|
||||
|
||||
También podrías definirla como una función normal en lugar de `async def`:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
@@ -342,7 +342,7 @@ Si no sabes la diferencia, Revisa la sección [Async: *"¿Tienes prisa?"*](../as
|
||||
|
||||
### Paso 5: retorna el contenido { #step-5-return-the-content }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}
|
||||
|
||||
Puedes retornar un `dict`, `list`, valores singulares como `str`, `int`, etc.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Para devolver responses HTTP con errores al cliente, usa `HTTPException`.
|
||||
|
||||
### Importa `HTTPException` { #import-httpexception }
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *}
|
||||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
|
||||
|
||||
### Lanza un `HTTPException` en tu código { #raise-an-httpexception-in-your-code }
|
||||
|
||||
@@ -39,7 +39,7 @@ El beneficio de lanzar una excepción en lugar de `return`ar un valor será más
|
||||
|
||||
En este ejemplo, cuando el cliente solicita un ítem por un ID que no existe, lanza una excepción con un código de estado de `404`:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *}
|
||||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
|
||||
|
||||
### El response resultante { #the-resulting-response }
|
||||
|
||||
@@ -77,7 +77,7 @@ Probablemente no necesitarás usarlos directamente en tu código.
|
||||
|
||||
Pero en caso de que los necesites para un escenario avanzado, puedes agregar headers personalizados:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *}
|
||||
{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
|
||||
|
||||
## Instalar manejadores de excepciones personalizados { #install-custom-exception-handlers }
|
||||
|
||||
@@ -89,7 +89,7 @@ Y quieres manejar esta excepción globalmente con FastAPI.
|
||||
|
||||
Podrías agregar un manejador de excepciones personalizado con `@app.exception_handler()`:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *}
|
||||
{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
|
||||
|
||||
Aquí, si solicitas `/unicorns/yolo`, la *path operation* lanzará un `UnicornException`.
|
||||
|
||||
@@ -127,7 +127,7 @@ Para sobrescribirlo, importa el `RequestValidationError` y úsalo con `@app.exce
|
||||
|
||||
El manejador de excepciones recibirá un `Request` y la excepción.
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *}
|
||||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
|
||||
|
||||
Ahora, si vas a `/items/foo`, en lugar de obtener el error JSON por defecto con:
|
||||
|
||||
@@ -159,7 +159,7 @@ De la misma manera, puedes sobrescribir el manejador de `HTTPException`.
|
||||
|
||||
Por ejemplo, podrías querer devolver un response de texto plano en lugar de JSON para estos errores:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *}
|
||||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
|
||||
|
||||
/// note | Nota Técnica
|
||||
|
||||
@@ -183,7 +183,7 @@ El `RequestValidationError` contiene el `body` que recibió con datos inválidos
|
||||
|
||||
Podrías usarlo mientras desarrollas tu aplicación para registrar el body y depurarlo, devolverlo al usuario, etc.
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *}
|
||||
{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
|
||||
|
||||
Ahora intenta enviar un ítem inválido como:
|
||||
|
||||
@@ -239,6 +239,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
|
||||
Si quieres usar la excepción junto con los mismos manejadores de excepciones predeterminados de **FastAPI**, puedes importar y reutilizar los manejadores de excepciones predeterminados de `fastapi.exception_handlers`:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *}
|
||||
{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
|
||||
|
||||
En este ejemplo solo estás `print`eando el error con un mensaje muy expresivo, pero te haces una idea. Puedes usar la excepción y luego simplemente reutilizar los manejadores de excepciones predeterminados.
|
||||
|
||||
@@ -18,7 +18,7 @@ Puedes establecer los siguientes campos que se usan en la especificación OpenAP
|
||||
|
||||
Puedes configurarlos de la siguiente manera:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *}
|
||||
{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -36,7 +36,7 @@ Desde OpenAPI 3.1.0 y FastAPI 0.99.0, también puedes establecer la `license_inf
|
||||
|
||||
Por ejemplo:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *}
|
||||
{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}
|
||||
|
||||
## Metadata para etiquetas { #metadata-for-tags }
|
||||
|
||||
@@ -58,7 +58,7 @@ Probemos eso en un ejemplo con etiquetas para `users` y `items`.
|
||||
|
||||
Crea metadata para tus etiquetas y pásala al parámetro `openapi_tags`:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *}
|
||||
{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}
|
||||
|
||||
Nota que puedes utilizar Markdown dentro de las descripciones, por ejemplo "login" se mostrará en negrita (**login**) y "fancy" se mostrará en cursiva (_fancy_).
|
||||
|
||||
@@ -72,7 +72,7 @@ No tienes que agregar metadata para todas las etiquetas que uses.
|
||||
|
||||
Usa el parámetro `tags` con tus *path operations* (y `APIRouter`s) para asignarlas a diferentes etiquetas:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *}
|
||||
{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
|
||||
|
||||
/// info | Información
|
||||
|
||||
@@ -100,7 +100,7 @@ Pero puedes configurarlo con el parámetro `openapi_url`.
|
||||
|
||||
Por ejemplo, para configurarlo para que se sirva en `/api/v1/openapi.json`:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *}
|
||||
{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
|
||||
|
||||
Si quieres deshabilitar el esquema OpenAPI completamente, puedes establecer `openapi_url=None`, eso también deshabilitará las interfaces de usuario de documentación que lo usan.
|
||||
|
||||
@@ -117,4 +117,4 @@ Puedes configurar las dos interfaces de usuario de documentación incluidas:
|
||||
|
||||
Por ejemplo, para configurar Swagger UI para que se sirva en `/documentation` y deshabilitar ReDoc:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *}
|
||||
{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
|
||||
|
||||
@@ -31,7 +31,7 @@ La función middleware recibe:
|
||||
* Luego devuelve la `response` generada por la correspondiente *path operation*.
|
||||
* Puedes entonces modificar aún más la `response` antes de devolverla.
|
||||
|
||||
{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *}
|
||||
{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -57,7 +57,7 @@ Y también después de que se genere la `response`, antes de devolverla.
|
||||
|
||||
Por ejemplo, podrías añadir un custom header `X-Process-Time` que contenga el tiempo en segundos que tomó procesar la request y generar una response:
|
||||
|
||||
{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *}
|
||||
{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ En estos casos, podría tener sentido almacenar las tags en un `Enum`.
|
||||
|
||||
**FastAPI** soporta eso de la misma manera que con strings normales:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}
|
||||
|
||||
## Resumen y Descripción { #summary-and-description }
|
||||
|
||||
@@ -56,7 +56,7 @@ Puedes añadir un `summary` y `description`:
|
||||
|
||||
## Descripción desde docstring { #description-from-docstring }
|
||||
|
||||
Como las descripciones tienden a ser largas y cubrir múltiples líneas, puedes declarar la descripción de la *path operation* en la <abbr title="un string de múltiples líneas como la primera expresión dentro de una función (no asignada a ninguna variable) usada para documentación">docstring</abbr> de la función y **FastAPI** la leerá desde allí.
|
||||
Como las descripciones tienden a ser largas y cubrir múltiples líneas, puedes declarar la descripción de la *path operation* en la <dfn title="un string de múltiples líneas como la primera expresión dentro de una función (no asignada a ninguna variable) usada para documentación">docstring</dfn> de la función y **FastAPI** la leerá desde allí.
|
||||
|
||||
Puedes escribir <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a> en el docstring, se interpretará y mostrará correctamente (teniendo en cuenta la indentación del docstring).
|
||||
|
||||
@@ -90,9 +90,9 @@ Entonces, si no proporcionas una, **FastAPI** generará automáticamente una de
|
||||
|
||||
## Deprecar una *path operation* { #deprecate-a-path-operation }
|
||||
|
||||
Si necesitas marcar una *path operation* como <abbr title="obsoleta, se recomienda no usarla">deprecated</abbr>, pero sin eliminarla, pasa el parámetro `deprecated`:
|
||||
Si necesitas marcar una *path operation* como <dfn title="obsoleta, se recomienda no usarla">deprecated</dfn>, pero sin eliminarla, pasa el parámetro `deprecated`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
|
||||
|
||||
Se marcará claramente como deprecado en la documentación interactiva:
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
De la misma manera que puedes declarar más validaciones y metadatos para los parámetros de query con `Query`, puedes declarar el mismo tipo de validaciones y metadatos para los parámetros de path con `Path`.
|
||||
|
||||
## Importar Path { #import-path }
|
||||
## Importar `Path` { #import-path }
|
||||
|
||||
Primero, importa `Path` de `fastapi`, e importa `Annotated`:
|
||||
|
||||
@@ -46,19 +46,19 @@ Y no necesitas declarar nada más para ese parámetro, así que realmente no nec
|
||||
|
||||
Pero aún necesitas usar `Path` para el parámetro de path `item_id`. Y no quieres usar `Annotated` por alguna razón.
|
||||
|
||||
Python se quejará si pones un valor con un "default" antes de un valor que no tenga un "default".
|
||||
Python se quejará si pones un valor con "por defecto" antes de un valor que no tenga "por defecto".
|
||||
|
||||
Pero puedes reordenarlos y poner el valor sin un default (el parámetro de query `q`) primero.
|
||||
Pero puedes reordenarlos y poner el valor sin un valor por defecto (el parámetro de query `q`) primero.
|
||||
|
||||
No importa para **FastAPI**. Detectará los parámetros por sus nombres, tipos y declaraciones por defecto (`Query`, `Path`, etc.), no le importa el orden.
|
||||
No importa para **FastAPI**. Detectará los parámetros por sus nombres, tipos y declaraciones por defecto (`Query`, `Path`, etc), no le importa el orden.
|
||||
|
||||
Así que puedes declarar tu función como:
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
|
||||
|
||||
Pero ten en cuenta que si usas `Annotated`, no tendrás este problema, no importará ya que no estás usando los valores por defecto de los parámetros de la función para `Query()` o `Path()`.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
|
||||
|
||||
## Ordena los parámetros como necesites, trucos { #order-the-parameters-as-you-need-tricks }
|
||||
|
||||
@@ -83,13 +83,13 @@ Pasa `*`, como el primer parámetro de la función.
|
||||
|
||||
Python no hará nada con ese `*`, pero sabrá que todos los parámetros siguientes deben ser llamados como argumentos de palabras clave (parejas key-value), también conocidos como <abbr title="De: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Incluso si no tienen un valor por defecto.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
|
||||
|
||||
### Mejor con `Annotated` { #better-with-annotated }
|
||||
|
||||
Ten en cuenta que si usas `Annotated`, como no estás usando valores por defecto de los parámetros de la función, no tendrás este problema y probablemente no necesitarás usar `*`.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
|
||||
|
||||
## Validaciones numéricas: mayor o igual { #number-validations-greater-than-or-equal }
|
||||
|
||||
@@ -97,7 +97,7 @@ Con `Query` y `Path` (y otros que verás más adelante) puedes declarar restricc
|
||||
|
||||
Aquí, con `ge=1`, `item_id` necesitará ser un número entero "`g`reater than or `e`qual" a `1`.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
|
||||
|
||||
## Validaciones numéricas: mayor que y menor o igual { #number-validations-greater-than-and-less-than-or-equal }
|
||||
|
||||
@@ -106,19 +106,19 @@ Lo mismo aplica para:
|
||||
* `gt`: `g`reater `t`han
|
||||
* `le`: `l`ess than or `e`qual
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
|
||||
|
||||
## Validaciones numéricas: flotantes, mayor y menor { #number-validations-floats-greater-than-and-less-than }
|
||||
|
||||
Las validaciones numéricas también funcionan para valores `float`.
|
||||
|
||||
Aquí es donde se convierte en importante poder declarar <abbr title="greater than – mayor que"><code>gt</code></abbr> y no solo <abbr title="greater than or equal – mayor o igual que"><code>ge</code></abbr>. Ya que con esto puedes requerir, por ejemplo, que un valor sea mayor que `0`, incluso si es menor que `1`.
|
||||
Aquí es donde se convierte en importante poder declarar <abbr title="greater than - mayor que"><code>gt</code></abbr> y no solo <abbr title="greater than or equal - mayor o igual que"><code>ge</code></abbr>. Ya que con esto puedes requerir, por ejemplo, que un valor sea mayor que `0`, incluso si es menor que `1`.
|
||||
|
||||
Así, `0.5` sería un valor válido. Pero `0.0` o `0` no lo serían.
|
||||
|
||||
Y lo mismo para <abbr title="less than – menor que"><code>lt</code></abbr>.
|
||||
Y lo mismo para <abbr title="less than - menor que"><code>lt</code></abbr>.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
|
||||
|
||||
## Resumen { #recap }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Puedes declarar "parámetros" o "variables" de path con la misma sintaxis que se usa en los format strings de Python:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
|
||||
{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
|
||||
|
||||
El valor del parámetro de path `item_id` se pasará a tu función como el argumento `item_id`.
|
||||
|
||||
@@ -16,7 +16,7 @@ Así que, si ejecutas este ejemplo y vas a <a href="http://127.0.0.1:8000/items/
|
||||
|
||||
Puedes declarar el tipo de un parámetro de path en la función, usando anotaciones de tipos estándar de Python:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
|
||||
{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}
|
||||
|
||||
En este caso, `item_id` se declara como un `int`.
|
||||
|
||||
@@ -26,7 +26,7 @@ Esto te dará soporte del editor dentro de tu función, con chequeo de errores,
|
||||
|
||||
///
|
||||
|
||||
## <abbr title="también conocido como: serialización, parsing, marshalling">Conversión</abbr> de datos { #data-conversion }
|
||||
## <dfn title="también conocido como: serialización, parsing, marshalling">Conversión</dfn> de datos { #data-conversion }
|
||||
|
||||
Si ejecutas este ejemplo y abres tu navegador en <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, verás un response de:
|
||||
|
||||
@@ -38,7 +38,7 @@ Si ejecutas este ejemplo y abres tu navegador en <a href="http://127.0.0.1:8000/
|
||||
|
||||
Nota que el valor que tu función recibió (y devolvió) es `3`, como un `int` de Python, no un string `"3"`.
|
||||
|
||||
Entonces, con esa declaración de tipo, **FastAPI** te ofrece <abbr title="convertir el string que viene de un request HTTP en datos de Python">"parsing"</abbr> automático de request.
|
||||
Entonces, con esa declaración de tipo, **FastAPI** te ofrece <dfn title="convertir el string que viene de un request HTTP en datos de Python">"parsing"</dfn> automático de request.
|
||||
|
||||
///
|
||||
|
||||
@@ -118,13 +118,13 @@ Y luego también puedes tener un path `/users/{user_id}` para obtener datos sobr
|
||||
|
||||
Debido a que las *path operations* se evalúan en orden, necesitas asegurarte de que el path para `/users/me` se declara antes que el de `/users/{user_id}`:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
|
||||
{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}
|
||||
|
||||
De lo contrario, el path para `/users/{user_id}` también coincidiría para `/users/me`, "pensando" que está recibiendo un parámetro `user_id` con un valor de `"me"`.
|
||||
|
||||
De manera similar, no puedes redefinir una path operation:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
|
||||
{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}
|
||||
|
||||
La primera siempre será utilizada ya que el path coincide primero.
|
||||
|
||||
@@ -140,11 +140,11 @@ Al heredar de `str`, la documentación de la API podrá saber que los valores de
|
||||
|
||||
Luego crea atributos de clase con valores fijos, que serán los valores válidos disponibles:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
Si te estás preguntando, "AlexNet", "ResNet" y "LeNet" son solo nombres de <abbr title="Técnicamente, arquitecturas de modelos de Deep Learning">modelos</abbr> de Machine Learning.
|
||||
Si te estás preguntando, "AlexNet", "ResNet" y "LeNet" son solo nombres de <dfn title="Técnicamente, arquitecturas de modelos de Deep Learning">modelos</dfn> de Machine Learning.
|
||||
|
||||
///
|
||||
|
||||
@@ -152,7 +152,7 @@ Si te estás preguntando, "AlexNet", "ResNet" y "LeNet" son solo nombres de <abb
|
||||
|
||||
Luego crea un *path parameter* con una anotación de tipo usando la clase enum que creaste (`ModelName`):
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}
|
||||
|
||||
### Revisa la documentación { #check-the-docs }
|
||||
|
||||
@@ -168,13 +168,13 @@ El valor del *path parameter* será un *miembro* de enumeración.
|
||||
|
||||
Puedes compararlo con el *miembro* de enumeración en tu enum creada `ModelName`:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}
|
||||
|
||||
#### Obtener el valor de *enumeración* { #get-the-enumeration-value }
|
||||
|
||||
Puedes obtener el valor actual (un `str` en este caso) usando `model_name.value`, o en general, `your_enum_member.value`:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -188,7 +188,7 @@ Puedes devolver *miembros de enum* desde tu *path operation*, incluso anidados e
|
||||
|
||||
Serán convertidos a sus valores correspondientes (cadenas en este caso) antes de devolverlos al cliente:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}
|
||||
|
||||
En tu cliente recibirás un response JSON como:
|
||||
|
||||
@@ -227,7 +227,7 @@ En este caso, el nombre del parámetro es `file_path`, y la última parte, `:pat
|
||||
|
||||
Así que, puedes usarlo con:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -242,7 +242,7 @@ En ese caso, la URL sería: `/files//home/johndoe/myfile.txt`, con una doble bar
|
||||
Con **FastAPI**, al usar declaraciones de tipo estándar de Python, cortas e intuitivas, obtienes:
|
||||
|
||||
* Soporte del editor: chequeo de errores, autocompletado, etc.
|
||||
* "<abbr title="convertir el string que viene de un request HTTP en datos de Python">parsing</abbr>" de datos
|
||||
* " <dfn title="convertir el string que viene de un request HTTP en datos de Python">parsing</dfn> " de datos
|
||||
* Validación de datos
|
||||
* Anotación de API y documentación automática
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Tener `str | None` permitirá que tu editor te dé un mejor soporte y detecte er
|
||||
|
||||
## Validaciones adicionales { #additional-validation }
|
||||
|
||||
Vamos a hacer que, aunque `q` sea opcional, siempre que se proporcione, **su longitud no exceda los 50 caracteres**.
|
||||
Vamos a hacer que, aunque `q` sea opcional, siempre que se proporcione, su longitud no exceda los 50 caracteres.
|
||||
|
||||
### Importar `Query` y `Annotated` { #import-query-and-annotated }
|
||||
|
||||
@@ -47,40 +47,16 @@ Ahora es el momento de usarlo con FastAPI. 🚀
|
||||
|
||||
Teníamos esta anotación de tipo:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
Lo que haremos es envolver eso con `Annotated`, para que se convierta en:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
q: Annotated[str | None] = None
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python
|
||||
q: Annotated[Union[str, None]] = None
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
Ambas versiones significan lo mismo, `q` es un parámetro que puede ser un `str` o `None`, y por defecto, es `None`.
|
||||
|
||||
Ahora vamos a lo divertido. 🎉
|
||||
@@ -93,7 +69,7 @@ Ahora que tenemos este `Annotated` donde podemos poner más información (en est
|
||||
|
||||
Nota que el valor por defecto sigue siendo `None`, por lo que el parámetro sigue siendo opcional.
|
||||
|
||||
Pero ahora, al tener `Query(max_length=50)` dentro de `Annotated`, le estamos diciendo a FastAPI que queremos que tenga **validación adicional** para este valor, queremos que tenga un máximo de 50 caracteres. 😎
|
||||
Pero ahora, al tener `Query(max_length=50)` dentro de `Annotated`, le estamos diciendo a FastAPI que queremos que tenga validación adicional para este valor, queremos que tenga un máximo de 50 caracteres. 😎
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -103,13 +79,13 @@ Aquí estamos usando `Query()` porque este es un **parámetro de query**. Más a
|
||||
|
||||
FastAPI ahora:
|
||||
|
||||
* **Validará** los datos asegurándose de que la longitud máxima sea de 50 caracteres
|
||||
* Mostrará un **error claro** para el cliente cuando los datos no sean válidos
|
||||
* **Documentará** el parámetro en el OpenAPI esquema *path operation* (así aparecerá en la **UI de documentación automática**)
|
||||
* Validará los datos asegurándose de que la longitud máxima sea de 50 caracteres
|
||||
* Mostrará un error claro para el cliente cuando los datos no sean válidos
|
||||
* Documentará el parámetro en el OpenAPI esquema *path operation* (así aparecerá en la UI de documentación automática)
|
||||
|
||||
## Alternativa (antigua): `Query` como valor por defecto { #alternative-old-query-as-the-default-value }
|
||||
|
||||
Versiones anteriores de FastAPI (antes de <abbr title="before 2023-03 - antes de 2023-03">0.95.0</abbr>) requerían que usaras `Query` como el valor por defecto de tu parámetro, en lugar de ponerlo en `Annotated`, hay una alta probabilidad de que veas código usándolo alrededor, así que te lo explicaré.
|
||||
Versiones anteriores de FastAPI (antes de <dfn title="antes de 2023-03">0.95.0</dfn>) requerían que usaras `Query` como el valor por defecto de tu parámetro, en lugar de ponerlo en `Annotated`, hay una alta probabilidad de que veas código usándolo alrededor, así que te lo explicaré.
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -174,13 +150,13 @@ q: str = Query(default="rick")
|
||||
|
||||
### Ventajas de `Annotated` { #advantages-of-annotated }
|
||||
|
||||
**Usar `Annotated` es recomendado** en lugar del valor por defecto en los parámetros de función, es **mejor** por múltiples razones. 🤓
|
||||
Usar `Annotated` es recomendado en lugar del valor por defecto en los parámetros de función, es mejor por múltiples razones. 🤓
|
||||
|
||||
El valor **por defecto** del **parámetro de función** es el valor **real por defecto**, eso es más intuitivo con Python en general. 😌
|
||||
El valor por defecto del parámetro de función es el valor real por defecto, eso es más intuitivo con Python en general. 😌
|
||||
|
||||
Podrías **llamar** a esa misma función en **otros lugares** sin FastAPI, y **funcionaría como se espera**. Si hay un parámetro **requerido** (sin un valor por defecto), tu **editor** te avisará con un error, **Python** también se quejará si lo ejecutas sin pasar el parámetro requerido.
|
||||
Podrías llamar a esa misma función en otros lugares sin FastAPI, y funcionaría como se espera. Si hay un parámetro requerido (sin un valor por defecto), tu editor te avisará con un error, Python también se quejará si lo ejecutas sin pasar el parámetro requerido.
|
||||
|
||||
Cuando no usas `Annotated` y en su lugar usas el estilo de valor por defecto **(antiguo)**, si llamas a esa función sin FastAPI en **otros lugares**, tienes que **recordar** pasar los argumentos a la función para que funcione correctamente, de lo contrario, los valores serán diferentes de lo que esperas (por ejemplo, `QueryInfo` o algo similar en lugar de `str`). Y tu editor no se quejará, y Python no se quejará al ejecutar esa función, solo cuando los errores dentro de las operaciones hagan que funcione incorrectamente.
|
||||
Cuando no usas `Annotated` y en su lugar usas el estilo de valor por defecto (antiguo), si llamas a esa función sin FastAPI en otros lugares, tienes que recordar pasar los argumentos a la función para que funcione correctamente, de lo contrario, los valores serán diferentes de lo que esperas (por ejemplo, `QueryInfo` o algo similar en lugar de `str`). Y tu editor no se quejará, y Python no se quejará al ejecutar esa función, solo cuando los errores dentro de las operaciones hagan que funcione incorrectamente.
|
||||
|
||||
Dado que `Annotated` puede tener más de una anotación de metadato, ahora podrías incluso usar la misma función con otras herramientas, como <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
|
||||
|
||||
@@ -192,7 +168,7 @@ También puedes agregar un parámetro `min_length`:
|
||||
|
||||
## Agregar expresiones regulares { #add-regular-expressions }
|
||||
|
||||
Puedes definir una <abbr title="Una expresión regular, regex o regexp es una secuencia de caracteres que define un patrón de búsqueda para strings.">expresión regular</abbr> `pattern` que el parámetro debe coincidir:
|
||||
Puedes definir una <dfn title="Una expresión regular, regex o regexp es una secuencia de caracteres que define un patrón de búsqueda para strings.">expresión regular</dfn> `pattern` que el parámetro debe coincidir:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
@@ -202,7 +178,7 @@ Este patrón específico de expresión regular comprueba que el valor recibido d
|
||||
* `fixedquery`: tiene el valor exacto `fixedquery`.
|
||||
* `$`: termina allí, no tiene más caracteres después de `fixedquery`.
|
||||
|
||||
Si te sientes perdido con todas estas ideas de **"expresión regular"**, no te preocupes. Son un tema difícil para muchas personas. Aún puedes hacer muchas cosas sin necesitar expresiones regulares todavía.
|
||||
Si te sientes perdido con todas estas ideas de "expresión regular", no te preocupes. Son un tema difícil para muchas personas. Aún puedes hacer muchas cosas sin necesitar expresiones regulares todavía.
|
||||
|
||||
Ahora sabes que cuando las necesites puedes usarlas en **FastAPI**.
|
||||
|
||||
@@ -212,7 +188,7 @@ Puedes, por supuesto, usar valores por defecto diferentes de `None`.
|
||||
|
||||
Digamos que quieres declarar el parámetro de query `q` para que tenga un `min_length` de `3`, y para que tenga un valor por defecto de `"fixedquery"`:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
@@ -242,7 +218,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
|
||||
|
||||
Así que, cuando necesites declarar un valor como requerido mientras usas `Query`, simplemente puedes no declarar un valor por defecto:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
|
||||
|
||||
### Requerido, puede ser `None` { #required-can-be-none }
|
||||
|
||||
@@ -293,7 +269,7 @@ La documentación interactiva de API se actualizará en consecuencia, para permi
|
||||
|
||||
También puedes definir un valor por defecto `list` de valores si no se proporciona ninguno:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
|
||||
|
||||
Si vas a:
|
||||
|
||||
@@ -316,7 +292,7 @@ el valor por defecto de `q` será: `["foo", "bar"]` y tu response será:
|
||||
|
||||
También puedes usar `list` directamente en lugar de `list[str]`:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
@@ -372,7 +348,7 @@ Entonces puedes declarar un `alias`, y ese alias será usado para encontrar el v
|
||||
|
||||
Ahora digamos que ya no te gusta este parámetro.
|
||||
|
||||
Tienes que dejarlo allí por un tiempo porque hay clientes usándolo, pero quieres que la documentación lo muestre claramente como <abbr title="obsolete, recommended not to use it - obsoleto, se recomienda no usarlo">deprecated</abbr>.
|
||||
Tienes que dejarlo allí por un tiempo porque hay clientes usándolo, pero quieres que la documentación lo muestre claramente como <dfn title="obsoleto, se recomienda no usarlo">obsoleto</dfn>.
|
||||
|
||||
Luego pasa el parámetro `deprecated=True` a `Query`:
|
||||
|
||||
@@ -390,9 +366,9 @@ Para excluir un parámetro de query del esquema de OpenAPI generado (y por lo ta
|
||||
|
||||
## Validación personalizada { #custom-validation }
|
||||
|
||||
Podría haber casos donde necesites hacer alguna **validación personalizada** que no puede hacerse con los parámetros mostrados arriba.
|
||||
Podría haber casos donde necesites hacer alguna validación personalizada que no puede hacerse con los parámetros mostrados arriba.
|
||||
|
||||
En esos casos, puedes usar una **función validadora personalizada** que se aplique después de la validación normal (por ejemplo, después de validar que el valor es un `str`).
|
||||
En esos casos, puedes usar una función validadora personalizada que se aplique después de la validación normal (por ejemplo, después de validar que el valor es un `str`).
|
||||
|
||||
Puedes lograr eso usando <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">`AfterValidator` de Pydantic</a> dentro de `Annotated`.
|
||||
|
||||
@@ -402,7 +378,7 @@ Pydantic también tiene <a href="https://docs.pydantic.dev/latest/concepts/valid
|
||||
|
||||
///
|
||||
|
||||
Por ejemplo, este validador personalizado comprueba que el ID del ítem empiece con `isbn-` para un número de libro <abbr title="ISBN means International Standard Book Number - ISBN significa International Standard Book Number">ISBN</abbr> o con `imdb-` para un ID de URL de película de <abbr title="IMDB (Internet Movie Database) is a website with information about movies - IMDB (Internet Movie Database) es un sitio web con información sobre películas">IMDB</abbr>:
|
||||
Por ejemplo, este validador personalizado comprueba que el ID del ítem empiece con `isbn-` para un número de libro <abbr title="International Standard Book Number - Número Estándar Internacional de Libros">ISBN</abbr> o con `imdb-` para un ID de URL de película de <abbr title="Internet Movie Database - Base de datos de películas en Internet: un sitio web con información sobre películas">IMDB</abbr>:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
@@ -414,15 +390,15 @@ Esto está disponible con Pydantic versión 2 o superior. 😎
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
Si necesitas hacer cualquier tipo de validación que requiera comunicarte con algún **componente externo**, como una base de datos u otra API, deberías usar **Dependencias de FastAPI**, las aprenderás más adelante.
|
||||
Si necesitas hacer cualquier tipo de validación que requiera comunicarte con algún componente externo, como una base de datos u otra API, deberías usar Dependencias de FastAPI, las aprenderás más adelante.
|
||||
|
||||
Estos validadores personalizados son para cosas que pueden comprobarse **solo** con los **mismos datos** provistos en el request.
|
||||
Estos validadores personalizados son para cosas que pueden comprobarse solo con los mismos datos provistos en el request.
|
||||
|
||||
///
|
||||
|
||||
### Entiende ese código { #understand-that-code }
|
||||
|
||||
El punto importante es solo usar **`AfterValidator` con una función dentro de `Annotated`**. Si quieres, sáltate esta parte. 🤸
|
||||
El punto importante es solo usar `AfterValidator` con una función dentro de `Annotated`. Si quieres, sáltate esta parte. 🤸
|
||||
|
||||
---
|
||||
|
||||
@@ -436,17 +412,17 @@ Pero si te da curiosidad este ejemplo de código específico y sigues entretenid
|
||||
|
||||
#### Un ítem aleatorio { #a-random-item }
|
||||
|
||||
Con `data.items()` obtenemos un <abbr title="Algo que podemos iterar con un for loop, como una list, set, etc.">objeto iterable</abbr> con tuplas que contienen la clave y el valor para cada elemento del diccionario.
|
||||
Con `data.items()` obtenemos un <dfn title="Algo que podemos iterar con un for loop, como una list, set, etc.">objeto iterable</dfn> con tuplas que contienen la clave y el valor para cada elemento del diccionario.
|
||||
|
||||
Convertimos este objeto iterable en una `list` propiamente dicha con `list(data.items())`.
|
||||
|
||||
Luego con `random.choice()` podemos obtener un **valor aleatorio** de la lista, así que obtenemos una tupla con `(id, name)`. Será algo como `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||||
Luego con `random.choice()` podemos obtener un valor aleatorio de la lista, así que obtenemos una tupla con `(id, name)`. Será algo como `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||||
|
||||
Luego **asignamos esos dos valores** de la tupla a las variables `id` y `name`.
|
||||
Luego asignamos esos dos valores de la tupla a las variables `id` y `name`.
|
||||
|
||||
Así, si el usuario no proporcionó un ID de ítem, aún recibirá una sugerencia aleatoria.
|
||||
|
||||
...hacemos todo esto en una **sola línea simple**. 🤯 ¿No te encanta Python? 🐍
|
||||
...hacemos todo esto en una sola línea simple. 🤯 ¿No te encanta Python? 🐍
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Cuando declaras otros parámetros de función que no son parte de los parámetros de path, son automáticamente interpretados como parámetros de "query".
|
||||
|
||||
{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
|
||||
|
||||
La query es el conjunto de pares clave-valor que van después del `?` en una URL, separados por caracteres `&`.
|
||||
|
||||
@@ -24,7 +24,7 @@ Pero cuando los declaras con tipos de Python (en el ejemplo anterior, como `int`
|
||||
Todo el mismo proceso que se aplica para los parámetros de path también se aplica para los parámetros de query:
|
||||
|
||||
* Soporte del editor (obviamente)
|
||||
* <abbr title="convirtiendo el string que viene de un request HTTP en datos de Python">"parsing"</abbr> de datos
|
||||
* <dfn title="convirtiendo el string que viene de un request HTTP en datos de Python">"parsing"</dfn> de datos
|
||||
* Validación de datos
|
||||
* Documentación automática
|
||||
|
||||
@@ -127,7 +127,7 @@ Si no quieres agregar un valor específico pero solo hacer que sea opcional, est
|
||||
|
||||
Pero cuando quieres hacer un parámetro de query requerido, simplemente no declares ningún valor por defecto:
|
||||
|
||||
{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
|
||||
{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
|
||||
|
||||
Aquí el parámetro de query `needy` es un parámetro de query requerido de tipo `str`.
|
||||
|
||||
|
||||
@@ -20,13 +20,13 @@ Esto es porque los archivos subidos se envían como "form data".
|
||||
|
||||
Importa `File` y `UploadFile` desde `fastapi`:
|
||||
|
||||
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
|
||||
{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
## Definir Parámetros `File` { #define-file-parameters }
|
||||
|
||||
Crea parámetros de archivo de la misma manera que lo harías para `Body` o `Form`:
|
||||
|
||||
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
/// info | Información
|
||||
|
||||
@@ -54,7 +54,7 @@ Pero hay varios casos en los que podrías beneficiarte de usar `UploadFile`.
|
||||
|
||||
Define un parámetro de archivo con un tipo de `UploadFile`:
|
||||
|
||||
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
|
||||
{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}
|
||||
|
||||
Usar `UploadFile` tiene varias ventajas sobre `bytes`:
|
||||
|
||||
@@ -121,7 +121,7 @@ Los datos de los forms normalmente se codifican usando el "media type" `applicat
|
||||
|
||||
Pero cuando el formulario incluye archivos, se codifica como `multipart/form-data`. Si usas `File`, **FastAPI** sabrá que tiene que obtener los archivos de la parte correcta del cuerpo.
|
||||
|
||||
Si deseas leer más sobre estas codificaciones y campos de formularios, dirígete a la <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network – Red de Desarrolladores de Mozilla">MDN</abbr> web docs para <code>POST</code></a>.
|
||||
Si deseas leer más sobre estas codificaciones y campos de formularios, dirígete a la <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network - Red de Desarrolladores de Mozilla">MDN</abbr> web docs para <code>POST</code></a>.
|
||||
|
||||
///
|
||||
|
||||
@@ -143,7 +143,7 @@ Puedes hacer un archivo opcional utilizando anotaciones de tipos estándar y est
|
||||
|
||||
También puedes usar `File()` con `UploadFile`, por ejemplo, para establecer metadatos adicionales:
|
||||
|
||||
{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
|
||||
{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}
|
||||
|
||||
## Subidas de Múltiples Archivos { #multiple-file-uploads }
|
||||
|
||||
@@ -151,9 +151,9 @@ Es posible subir varios archivos al mismo tiempo.
|
||||
|
||||
Estarían asociados al mismo "campo de formulario" enviado usando "form data".
|
||||
|
||||
Para usar eso, declara una lista de `bytes` o `UploadFile`:
|
||||
Para usar eso, declara una `list` de `bytes` o `UploadFile`:
|
||||
|
||||
{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
|
||||
{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}
|
||||
|
||||
Recibirás, como se declaró, una `list` de `bytes` o `UploadFile`s.
|
||||
|
||||
@@ -169,7 +169,7 @@ También podrías usar `from starlette.responses import HTMLResponse`.
|
||||
|
||||
Y de la misma manera que antes, puedes usar `File()` para establecer parámetros adicionales, incluso para `UploadFile`:
|
||||
|
||||
{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
|
||||
{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}
|
||||
|
||||
## Recapitulación { #recap }
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Esto es compatible desde la versión `0.113.0` de FastAPI. 🤓
|
||||
|
||||
Solo necesitas declarar un **modelo de Pydantic** con los campos que quieres recibir como **campos de formulario**, y luego declarar el parámetro como `Form`:
|
||||
|
||||
{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
|
||||
{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}
|
||||
|
||||
**FastAPI** **extraerá** los datos de **cada campo** de los **form data** en el request y te dará el modelo de Pydantic que definiste.
|
||||
|
||||
@@ -48,7 +48,7 @@ Esto es compatible desde la versión `0.114.0` de FastAPI. 🤓
|
||||
|
||||
Puedes usar la configuración del modelo de Pydantic para `forbid` cualquier campo `extra`:
|
||||
|
||||
{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
|
||||
{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}
|
||||
|
||||
Si un cliente intenta enviar datos extra, recibirá un response de **error**.
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@ $ pip install python-multipart
|
||||
|
||||
## Importa `File` y `Form` { #import-file-and-form }
|
||||
|
||||
{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
|
||||
{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
## Define parámetros `File` y `Form` { #define-file-and-form-parameters }
|
||||
|
||||
Crea parámetros de archivo y formulario de la misma manera que lo harías para `Body` o `Query`:
|
||||
|
||||
{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
|
||||
{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}
|
||||
|
||||
Los archivos y campos de formulario se subirán como form data y recibirás los archivos y campos de formulario.
|
||||
|
||||
|
||||
@@ -18,17 +18,17 @@ $ pip install python-multipart
|
||||
|
||||
Importar `Form` desde `fastapi`:
|
||||
|
||||
{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
|
||||
{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
## Definir parámetros de `Form` { #define-form-parameters }
|
||||
|
||||
Crea parámetros de formulario de la misma manera que lo harías para `Body` o `Query`:
|
||||
|
||||
{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
Por ejemplo, en una de las formas en las que se puede usar la especificación OAuth2 (llamada "password flow") se requiere enviar un `username` y `password` como campos de formulario.
|
||||
|
||||
La <abbr title="specification – especificación">spec</abbr> requiere que los campos se llamen exactamente `username` y `password`, y que se envíen como campos de formulario, no JSON.
|
||||
La <dfn title="especificación">especificación</dfn> requiere que los campos se llamen exactamente `username` y `password`, y que se envíen como campos de formulario, no JSON.
|
||||
|
||||
Con `Form` puedes declarar las mismas configuraciones que con `Body` (y `Query`, `Path`, `Cookie`), incluyendo validación, ejemplos, un alias (por ejemplo, `user-name` en lugar de `username`), etc.
|
||||
|
||||
@@ -56,7 +56,7 @@ Los datos de formularios normalmente se codifican usando el "media type" `applic
|
||||
|
||||
Pero cuando el formulario incluye archivos, se codifica como `multipart/form-data`. Leerás sobre la gestión de archivos en el próximo capítulo.
|
||||
|
||||
Si quieres leer más sobre estas codificaciones y campos de formulario, dirígete a la <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network – Red de Desarrolladores de Mozilla">MDN</abbr> web docs para <code>POST</code></a>.
|
||||
Si quieres leer más sobre estas codificaciones y campos de formulario, dirígete a la <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network - Red de Desarrolladores de Mozilla">MDN</abbr> web docs para <code>POST</code></a>.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ FastAPI usará este `response_model` para hacer toda la documentación de datos,
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
Si tienes chequeos estrictos de tipos en tu editor, mypy, etc., puedes declarar el tipo de retorno de la función como `Any`.
|
||||
Si tienes chequeo de tipos estricto en tu editor, mypy, etc., puedes declarar el tipo de retorno de la función como `Any`.
|
||||
|
||||
De esa manera le dices al editor que intencionalmente estás devolviendo cualquier cosa. Pero FastAPI todavía hará la documentación de datos, validación, filtrado, etc. con `response_model`.
|
||||
|
||||
@@ -183,7 +183,7 @@ Podría haber casos en los que devuelvas algo que no es un campo válido de Pyda
|
||||
|
||||
El caso más común sería [devolver un Response directamente como se explica más adelante en la documentación avanzada](../advanced/response-directly.md){.internal-link target=_blank}.
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
|
||||
{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}
|
||||
|
||||
Este caso simple es manejado automáticamente por FastAPI porque la anotación del tipo de retorno es la clase (o una subclase de) `Response`.
|
||||
|
||||
@@ -193,7 +193,7 @@ Y las herramientas también estarán felices porque tanto `RedirectResponse` com
|
||||
|
||||
También puedes usar una subclase de `Response` en la anotación del tipo:
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
|
||||
{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}
|
||||
|
||||
Esto también funcionará porque `RedirectResponse` es una subclase de `Response`, y FastAPI manejará automáticamente este caso simple.
|
||||
|
||||
@@ -201,7 +201,7 @@ Esto también funcionará porque `RedirectResponse` es una subclase de `Response
|
||||
|
||||
Pero cuando devuelves algún otro objeto arbitrario que no es un tipo válido de Pydantic (por ejemplo, un objeto de base de datos) y lo anotas así en la función, FastAPI intentará crear un modelo de response de Pydantic a partir de esa anotación de tipo, y fallará.
|
||||
|
||||
Lo mismo sucedería si tuvieras algo como un <abbr title='Una unión entre múltiples tipos significa "cualquiera de estos tipos".'>union</abbr> entre diferentes tipos donde uno o más de ellos no son tipos válidos de Pydantic, por ejemplo esto fallaría 💥:
|
||||
Lo mismo sucedería si tuvieras algo como una <dfn title='una unión entre múltiples tipos significa "cualquiera de estos tipos".'>unión</dfn> entre diferentes tipos donde uno o más de ellos no son tipos válidos de Pydantic, por ejemplo esto fallaría 💥:
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ De la misma manera que puedes especificar un modelo de response, también puedes
|
||||
* `@app.delete()`
|
||||
* etc.
|
||||
|
||||
{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
|
||||
{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
@@ -66,7 +66,7 @@ En breve:
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
Para saber más sobre cada código de estado y qué código es para qué, revisa la <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank">documentación de <abbr title="Mozilla Developer Network – Red de Desarrolladores de Mozilla">MDN</abbr> sobre códigos de estado HTTP</a>.
|
||||
Para saber más sobre cada código de estado y qué código es para qué, revisa la <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank">documentación de <abbr title="Mozilla Developer Network - Red de Desarrolladores de Mozilla">MDN</abbr> sobre códigos de estado HTTP</a>.
|
||||
|
||||
///
|
||||
|
||||
@@ -74,7 +74,7 @@ Para saber más sobre cada código de estado y qué código es para qué, revisa
|
||||
|
||||
Veamos de nuevo el ejemplo anterior:
|
||||
|
||||
{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
|
||||
{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
|
||||
|
||||
`201` es el código de estado para "Created".
|
||||
|
||||
@@ -82,7 +82,7 @@ Pero no tienes que memorizar lo que significa cada uno de estos códigos.
|
||||
|
||||
Puedes usar las variables de conveniencia de `fastapi.status`.
|
||||
|
||||
{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
|
||||
{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
|
||||
|
||||
Son solo una conveniencia, mantienen el mismo número, pero de esa manera puedes usar el autocompletado del editor para encontrarlos:
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ Por supuesto, también puedes pasar múltiples `examples`:
|
||||
|
||||
Cuando haces esto, los ejemplos serán parte del **JSON Schema** interno para esos datos del body.
|
||||
|
||||
Sin embargo, al <abbr title="2023-08-26">momento de escribir esto</abbr>, Swagger UI, la herramienta encargada de mostrar la interfaz de documentación, no soporta mostrar múltiples ejemplos para los datos en **JSON Schema**. Pero lee más abajo para una solución alternativa.
|
||||
Sin embargo, al <dfn title="2023-08-26">momento de escribir esto</dfn>, Swagger UI, la herramienta encargada de mostrar la interfaz de documentación, no soporta mostrar múltiples ejemplos para los datos en **JSON Schema**. Pero lee más abajo para una solución alternativa.
|
||||
|
||||
### `examples` específicos de OpenAPI { #openapi-specific-examples }
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Primero solo usemos el código y veamos cómo funciona, y luego volveremos para
|
||||
|
||||
Copia el ejemplo en un archivo `main.py`:
|
||||
|
||||
{* ../../docs_src/security/tutorial001_an_py39.py *}
|
||||
{* ../../docs_src/security/tutorial001_an_py310.py *}
|
||||
|
||||
## Ejecútalo { #run-it }
|
||||
|
||||
@@ -132,7 +132,7 @@ En ese caso, **FastAPI** también te proporciona las herramientas para construir
|
||||
|
||||
Cuando creamos una instance de la clase `OAuth2PasswordBearer` pasamos el parámetro `tokenUrl`. Este parámetro contiene la URL que el cliente (el frontend corriendo en el navegador del usuario) usará para enviar el `username` y `password` a fin de obtener un token.
|
||||
|
||||
{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
|
||||
{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -170,7 +170,7 @@ Así que, puede usarse con `Depends`.
|
||||
|
||||
Ahora puedes pasar ese `oauth2_scheme` en una dependencia con `Depends`.
|
||||
|
||||
{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
|
||||
{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
|
||||
|
||||
Esta dependencia proporcionará un `str` que se asigna al parámetro `token` de la *path operation function*.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
En el capítulo anterior, el sistema de seguridad (que se basa en el sistema de inyección de dependencias) le estaba dando a la *path operation function* un `token` como un `str`:
|
||||
|
||||
{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
|
||||
{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
|
||||
|
||||
Pero eso aún no es tan útil. Vamos a hacer que nos dé el usuario actual.
|
||||
|
||||
|
||||
@@ -116,7 +116,11 @@ Y otra utilidad para verificar si una contraseña recibida coincide con el hash
|
||||
|
||||
Y otra más para autenticar y devolver un usuario.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
|
||||
|
||||
Cuando `authenticate_user` se llama con un nombre de usuario que no existe en la base de datos, aun así ejecutamos `verify_password` contra un hash ficticio.
|
||||
|
||||
Esto asegura que el endpoint tarda aproximadamente la misma cantidad de tiempo en responder tanto si el nombre de usuario es válido como si no, previniendo los **timing attacks** que podrían usarse para enumerar nombres de usuario existentes.
|
||||
|
||||
/// note | Nota
|
||||
|
||||
@@ -152,7 +156,7 @@ Define un Modelo de Pydantic que se usará en el endpoint de token para el respo
|
||||
|
||||
Crea una función de utilidad para generar un nuevo token de acceso.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
|
||||
|
||||
## Actualizar las dependencias { #update-the-dependencies }
|
||||
|
||||
@@ -162,7 +166,7 @@ Decodifica el token recibido, verifícalo y devuelve el usuario actual.
|
||||
|
||||
Si el token es inválido, devuelve un error HTTP de inmediato.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
|
||||
|
||||
## Actualizar la *path operation* `/token` { #update-the-token-path-operation }
|
||||
|
||||
@@ -170,7 +174,7 @@ Crea un `timedelta` con el tiempo de expiración del token.
|
||||
|
||||
Crea un verdadero token de acceso JWT y devuélvelo.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
|
||||
|
||||
### Detalles técnicos sobre el "sujeto" `sub` de JWT { #technical-details-about-the-jwt-subject-sub }
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Aquí veremos un ejemplo usando <a href="https://sqlmodel.tiangolo.com/" class="
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
Puedes usar cualquier otro paquete de bases de datos SQL o NoSQL que quieras (en algunos casos llamadas <abbr title="Object Relational Mapper – Mapeador Objeto-Relacional: un término elegante para un paquete donde algunas clases representan tablas SQL y las instances representan filas en esas tablas">"ORMs"</abbr>), FastAPI no te obliga a usar nada. 😎
|
||||
Puedes usar cualquier otro paquete de bases de datos SQL o NoSQL que quieras (en algunos casos llamadas <abbr title="Object Relational Mapper - Mapeador Objeto-Relacional: un término elegante para un paquete donde algunas clases representan tablas SQL y las instances representan filas en esas tablas">"ORMs"</abbr>), FastAPI no te obliga a usar nada. 😎
|
||||
|
||||
///
|
||||
|
||||
@@ -354,4 +354,4 @@ Si vas a la interfaz de `/docs` de la API, verás que ahora está actualizada, y
|
||||
|
||||
Puedes usar <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">**SQLModel**</a> para interactuar con una base de datos SQL y simplificar el código con *modelos de datos* y *modelos de tablas*.
|
||||
|
||||
Puedes aprender mucho más en la documentación de **SQLModel**, hay un mini <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">tutorial sobre el uso de SQLModel con **FastAPI**</a>. 🚀
|
||||
Puedes aprender mucho más en la documentación de **SQLModel**, hay un mini <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">tutorial más largo sobre el uso de SQLModel con **FastAPI**</a>. 🚀
|
||||
|
||||
@@ -7,7 +7,7 @@ Puedes servir archivos estáticos automáticamente desde un directorio utilizand
|
||||
* Importa `StaticFiles`.
|
||||
* "Monta" una instance de `StaticFiles()` en un path específico.
|
||||
|
||||
{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
|
||||
{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}
|
||||
|
||||
/// note | Detalles Técnicos
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Usa el objeto `TestClient` de la misma manera que con `httpx`.
|
||||
|
||||
Escribe declaraciones `assert` simples con las expresiones estándar de Python que necesites revisar (otra vez, estándar de `pytest`).
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
|
||||
{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -75,7 +75,7 @@ Digamos que tienes una estructura de archivos como se describe en [Aplicaciones
|
||||
|
||||
En el archivo `main.py` tienes tu aplicación de **FastAPI**:
|
||||
|
||||
{* ../../docs_src/app_testing/app_a_py39/main.py *}
|
||||
{* ../../docs_src/app_testing/app_a_py310/main.py *}
|
||||
|
||||
### Archivo de prueba { #testing-file }
|
||||
|
||||
@@ -91,7 +91,7 @@ Entonces podrías tener un archivo `test_main.py` con tus pruebas. Podría estar
|
||||
|
||||
Debido a que este archivo está en el mismo paquete, puedes usar importaciones relativas para importar el objeto `app` desde el módulo `main` (`main.py`):
|
||||
|
||||
{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
|
||||
{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
|
||||
|
||||
...y tener el código para las pruebas tal como antes.
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ $ cd awesome-project
|
||||
|
||||
## Crea un Entorno Virtual { #create-a-virtual-environment }
|
||||
|
||||
Cuando empiezas a trabajar en un proyecto de Python **por primera vez**, crea un entorno virtual **<abbr title="hay otras opciones, esto es solo una guía sencilla">dentro de tu proyecto</abbr>**.
|
||||
Cuando empiezas a trabajar en un proyecto de Python **por primera vez**, crea un entorno virtual **<dfn title="hay otras opciones, esto es solo una guía sencilla">dentro de tu proyecto</dfn>**.
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -170,9 +170,9 @@ Esto asegura que si usas un programa de **terminal (<abbr title="command line in
|
||||
|
||||
///
|
||||
|
||||
## Verifica que el Entorno Virtual esté Activo { #check-the-virtual-environment-is-active }
|
||||
## Revisa que el Entorno Virtual esté Activo { #check-the-virtual-environment-is-active }
|
||||
|
||||
Verifica que el entorno virtual esté activo (el comando anterior funcionó).
|
||||
Revisa que el entorno virtual esté activo (el comando anterior funcionó).
|
||||
|
||||
/// tip | Consejo
|
||||
|
||||
@@ -732,7 +732,7 @@ Un detalle importante es que pondrá el path del entorno virtual al **comienzo**
|
||||
|
||||
Activar un entorno virtual también cambia un par de otras cosas, pero esta es una de las cosas más importantes que hace.
|
||||
|
||||
## Verificando un Entorno Virtual { #checking-a-virtual-environment }
|
||||
## Revisando un Entorno Virtual { #checking-a-virtual-environment }
|
||||
|
||||
Cuando revisas si un entorno virtual está activo, por ejemplo con:
|
||||
|
||||
|
||||
503
docs/ja/docs/_llm-test.md
Normal file
503
docs/ja/docs/_llm-test.md
Normal file
@@ -0,0 +1,503 @@
|
||||
# LLM テストファイル { #llm-test-file }
|
||||
|
||||
このドキュメントは、ドキュメントを翻訳する <abbr title="Large Language Model - 大規模言語モデル">LLM</abbr> が、`scripts/translate.py` の `general_prompt` と、`docs/{language code}/llm-prompt.md` の言語固有プロンプトを理解しているかをテストします。言語固有プロンプトは `general_prompt` の末尾に追加されます。
|
||||
|
||||
ここに追加したテストは、すべての言語固有プロンプトの設計者が参照します。
|
||||
|
||||
使い方:
|
||||
|
||||
* 言語固有プロンプトを用意します - `docs/{language code}/llm-prompt.md`。
|
||||
* この文書を希望するターゲット言語に新規で翻訳します(例: `translate.py` の `translate-page` コマンド)。これにより `docs/{language code}/docs/_llm-test.md` に翻訳が作成されます。
|
||||
* 翻訳が問題ないか確認します。
|
||||
* 必要であれば、言語固有プロンプト、general プロンプト、または英語ドキュメントを改善します。
|
||||
* その後、翻訳に残っている問題を手動で修正し、良い翻訳にします。
|
||||
* 良い翻訳を用意した状態でもう一度翻訳します。理想的な結果は、LLM が翻訳に一切変更を加えないことです。つまり general プロンプトと言語固有プロンプトが最良であることを意味します(時々いくつかランダムに見える変更を行うことがあります。理由は <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM は決定論的アルゴリズムではない</a> ためです)。
|
||||
|
||||
テスト内容:
|
||||
|
||||
## コードスニペット { #code-snippets }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
これはコードスニペットです: `foo`。そしてこれもコードスニペットです: `bar`。さらにもう一つ: `baz quux`。
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
コードスニペットの内容はそのままにしておく必要があります。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Content of code snippets」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## 引用 { #quotes }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
昨日、友人はこう書きました。「incorrectly を正しく綴れば、あなたはそれを間違って綴ったことになる」。それに対して私はこう答えました。「そのとおり。ただし『incorrectly』は誤りで、『"incorrectly"』ではありません」。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
LLM はおそらくここを誤って翻訳します。重要なのは、再翻訳時に修正済みの翻訳を維持できるかどうかだけです。
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
プロンプト設計者は、ストレートクォートをタイポグラフィックな引用符に変換するかどうかを選べます。そのままでも問題ありません。
|
||||
|
||||
例として `docs/de/llm-prompt.md` の「### Quotes」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## コードスニペット内の引用 { #quotes-in-code-snippets }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
`pip install "foo[bar]"`
|
||||
|
||||
コードスニペット中の文字列リテラルの例: `"this"`, `'that'`.
|
||||
|
||||
難しい文字列リテラルの例: `f"I like {'oranges' if orange else "apples"}"`
|
||||
|
||||
ハードコア: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"`
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
... ただし、コードスニペット内の引用符はそのままにしておく必要があります。
|
||||
|
||||
////
|
||||
|
||||
## コードブロック { #code-blocks }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
Bash のコード例です...
|
||||
|
||||
```bash
|
||||
# 宇宙にあいさつを表示
|
||||
echo "Hello universe"
|
||||
```
|
||||
|
||||
...そしてコンソールのコード例です...
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting server
|
||||
Searching for package file structure
|
||||
```
|
||||
|
||||
...さらに別のコンソールのコード例です...
|
||||
|
||||
```console
|
||||
// ディレクトリ "code" を作成
|
||||
$ mkdir code
|
||||
// そのディレクトリに移動
|
||||
$ cd code
|
||||
```
|
||||
|
||||
...そして Python のコード例です...
|
||||
|
||||
```Python
|
||||
wont_work() # これは動作しません 😱
|
||||
works(foo="bar") # これは動作します 🎉
|
||||
```
|
||||
|
||||
...以上です。
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
コードブロック内のコードは、コメントを除き、変更してはいけません。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Content of code blocks」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## タブと色付きボックス { #tabs-and-colored-boxes }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
/// info | 情報
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// note | 備考
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// note | 技術詳細
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// check | 確認
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// tip | 豆知識
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// danger | 警告
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
タブおよび `Info`/`Note`/`Warning` などのブロックには、タイトルの翻訳を縦棒(`|`)の後ろに追加します。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Special blocks」と「### Tab blocks」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## Web リンクと内部リンク { #web-and-internal-links }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
リンクのテキストは翻訳し、リンク先のアドレスは変更しないでください:
|
||||
|
||||
* [上の見出しへのリンク](#code-snippets)
|
||||
* [内部リンク](index.md#installation){.internal-link target=_blank}
|
||||
* <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">外部リンク</a>
|
||||
* <a href="https://fastapi.tiangolo.com/css/styles.css" class="external-link" target="_blank">スタイルへのリンク</a>
|
||||
* <a href="https://fastapi.tiangolo.com/js/logic.js" class="external-link" target="_blank">スクリプトへのリンク</a>
|
||||
* <a href="https://fastapi.tiangolo.com/img/foo.jpg" class="external-link" target="_blank">画像へのリンク</a>
|
||||
|
||||
リンクのテキストは翻訳し、リンク先のアドレスは翻訳版を指すようにしてください:
|
||||
|
||||
* <a href="https://fastapi.tiangolo.com/ja/" class="external-link" target="_blank">FastAPI リンク</a>
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
リンクのテキストは翻訳し、アドレスは変更しないでください。例外は、FastAPI ドキュメントのページへの絶対 URL です。その場合は翻訳版へのリンクにします。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Links」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## HTML "abbr" 要素 { #html-abbr-elements }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
ここでは HTML の "abbr" 要素で包まれたものをいくつか示します(いくつかは架空です):
|
||||
|
||||
### abbr が完全な語句を示す { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done - 仕事を成し遂げること">GTD</abbr>
|
||||
* <abbr title="less than - より小さい"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token - XML ウェブトークン">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - 並列サーバーゲートウェイインターフェース">PSGI</abbr>
|
||||
|
||||
### abbr が完全な語句と説明を示す { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network - Mozilla 開発者ネットワーク: 開発者向けドキュメント、Firefox の開発元が執筆">MDN</abbr>
|
||||
* <abbr title="Input/Output - 入出力: ディスクの読み書き、ネットワーク通信。">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
"abbr" 要素の "title" 属性は特定の指示に従って翻訳します。
|
||||
|
||||
翻訳は、英語の語を説明するために独自の "abbr" 要素を追加してもよく、LLM はそれらを削除してはいけません。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### HTML abbr elements」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## HTML "dfn" 要素 { #html-dfn-elements }
|
||||
|
||||
* <dfn title="ある方法で接続・連携して動作するよう構成された複数のマシンの集合">クラスター</dfn>
|
||||
* <dfn title="入力層と出力層の間に多数の隠れ層を持つ人工ニューラルネットワークを用いる機械学習の手法で、その内部構造を包括的に形成する">ディープラーニング</dfn>
|
||||
|
||||
## 見出し { #headings }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
### Web アプリを開発する - チュートリアル { #develop-a-webapp-a-tutorial }
|
||||
|
||||
こんにちは。
|
||||
|
||||
### 型ヒントとアノテーション { #type-hints-and-annotations }
|
||||
|
||||
またこんにちは。
|
||||
|
||||
### スーパークラスとサブクラス { #super-and-subclasses }
|
||||
|
||||
またこんにちは。
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
見出しに関する唯一の厳格なルールは、リンクが壊れないように、LLM が中括弧内のハッシュ部分を変更しないことです。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Headings」の節を参照してください。
|
||||
|
||||
言語固有の指示については、例として `docs/de/llm-prompt.md` の「### Headings」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## ドキュメントで使う用語 { #terms-used-in-the-docs }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
* you
|
||||
* your
|
||||
|
||||
* e.g.
|
||||
* etc.
|
||||
|
||||
* `foo` を `int` として
|
||||
* `bar` を `str` として
|
||||
* `baz` を `list` として
|
||||
|
||||
* チュートリアル - ユーザーガイド
|
||||
* 上級ユーザーガイド
|
||||
* SQLModel ドキュメント
|
||||
* API ドキュメント
|
||||
* 自動生成ドキュメント
|
||||
|
||||
* データサイエンス
|
||||
* ディープラーニング
|
||||
* 機械学習
|
||||
* 依存性注入
|
||||
* HTTP Basic 認証
|
||||
* HTTP Digest
|
||||
* ISO 形式
|
||||
* JSON Schema 規格
|
||||
* JSON スキーマ
|
||||
* スキーマ定義
|
||||
* Password Flow
|
||||
* モバイル
|
||||
|
||||
* 非推奨
|
||||
* 設計された
|
||||
* 無効
|
||||
* オンザフライ
|
||||
* 標準
|
||||
* デフォルト
|
||||
* 大文字小文字を区別
|
||||
* 大文字小文字を区別しない
|
||||
|
||||
* アプリケーションを提供する
|
||||
* ページを配信する
|
||||
|
||||
* アプリ
|
||||
* アプリケーション
|
||||
|
||||
* リクエスト
|
||||
* レスポンス
|
||||
* エラーレスポンス
|
||||
|
||||
* path operation
|
||||
* path operation デコレータ
|
||||
* path operation 関数
|
||||
|
||||
* ボディ
|
||||
* リクエストボディ
|
||||
* レスポンスボディ
|
||||
* JSON ボディ
|
||||
* フォームボディ
|
||||
* ファイルボディ
|
||||
* 関数本体
|
||||
|
||||
* パラメータ
|
||||
* ボディパラメータ
|
||||
* パスパラメータ
|
||||
* クエリパラメータ
|
||||
* Cookie パラメータ
|
||||
* ヘッダーパラメータ
|
||||
* フォームパラメータ
|
||||
* 関数パラメータ
|
||||
|
||||
* イベント
|
||||
* 起動イベント
|
||||
* サーバーの起動
|
||||
* シャットダウンイベント
|
||||
* lifespan イベント
|
||||
|
||||
* ハンドラ
|
||||
* イベントハンドラ
|
||||
* 例外ハンドラ
|
||||
* 処理する
|
||||
|
||||
* モデル
|
||||
* Pydantic モデル
|
||||
* データモデル
|
||||
* データベースモデル
|
||||
* フォームモデル
|
||||
* モデルオブジェクト
|
||||
|
||||
* クラス
|
||||
* 基底クラス
|
||||
* 親クラス
|
||||
* サブクラス
|
||||
* 子クラス
|
||||
* 兄弟クラス
|
||||
* クラスメソッド
|
||||
|
||||
* ヘッダー
|
||||
* ヘッダー(複数)
|
||||
* 認可ヘッダー
|
||||
* `Authorization` ヘッダー
|
||||
* Forwarded ヘッダー
|
||||
|
||||
* 依存性注入システム
|
||||
* 依存関係
|
||||
* dependable
|
||||
* dependant
|
||||
|
||||
* I/O バウンド
|
||||
* CPU バウンド
|
||||
* 同時実行性
|
||||
* 並列性
|
||||
* マルチプロセッシング
|
||||
|
||||
* env var
|
||||
* 環境変数
|
||||
* `PATH`
|
||||
* `PATH` 環境変数
|
||||
|
||||
* 認証
|
||||
* 認証プロバイダ
|
||||
* 認可
|
||||
* 認可フォーム
|
||||
* 認可プロバイダ
|
||||
* ユーザーが認証する
|
||||
* システムがユーザーを認証する
|
||||
|
||||
* CLI
|
||||
* コマンドラインインターフェース
|
||||
|
||||
* サーバー
|
||||
* クライアント
|
||||
|
||||
* クラウドプロバイダ
|
||||
* クラウドサービス
|
||||
|
||||
* 開発
|
||||
* 開発段階
|
||||
|
||||
* dict
|
||||
* 辞書
|
||||
* 列挙型
|
||||
* Enum
|
||||
* 列挙メンバー
|
||||
|
||||
* エンコーダー
|
||||
* デコーダー
|
||||
* エンコードする
|
||||
* デコードする
|
||||
|
||||
* 例外
|
||||
* 送出する
|
||||
|
||||
* 式
|
||||
* 文
|
||||
|
||||
* フロントエンド
|
||||
* バックエンド
|
||||
|
||||
* GitHub ディスカッション
|
||||
* GitHub Issue
|
||||
|
||||
* パフォーマンス
|
||||
* パフォーマンス最適化
|
||||
|
||||
* 戻り値の型
|
||||
* 戻り値
|
||||
|
||||
* セキュリティ
|
||||
* セキュリティスキーム
|
||||
|
||||
* タスク
|
||||
* バックグラウンドタスク
|
||||
* タスク関数
|
||||
|
||||
* テンプレート
|
||||
* テンプレートエンジン
|
||||
|
||||
* 型アノテーション
|
||||
* 型ヒント
|
||||
|
||||
* サーバーワーカー
|
||||
* Uvicorn ワーカー
|
||||
* Gunicorn ワーカー
|
||||
* ワーカープロセス
|
||||
* ワーカークラス
|
||||
* ワークロード
|
||||
|
||||
* デプロイ
|
||||
* デプロイする
|
||||
|
||||
* SDK
|
||||
* ソフトウェア開発キット
|
||||
|
||||
* `APIRouter`
|
||||
* `requirements.txt`
|
||||
* Bearer Token
|
||||
* 破壊的変更
|
||||
* バグ
|
||||
* ボタン
|
||||
* 呼び出し可能
|
||||
* コード
|
||||
* コミット
|
||||
* コンテキストマネージャ
|
||||
* コルーチン
|
||||
* データベースセッション
|
||||
* ディスク
|
||||
* ドメイン
|
||||
* エンジン
|
||||
* フェイクの X
|
||||
* HTTP GET メソッド
|
||||
* アイテム
|
||||
* ライブラリ
|
||||
* ライフスパン
|
||||
* ロック
|
||||
* ミドルウェア
|
||||
* モバイルアプリケーション
|
||||
* モジュール
|
||||
* マウント
|
||||
* ネットワーク
|
||||
* オリジン
|
||||
* オーバーライド
|
||||
* ペイロード
|
||||
* プロセッサ
|
||||
* プロパティ
|
||||
* プロキシ
|
||||
* プルリクエスト
|
||||
* クエリ
|
||||
* RAM
|
||||
* リモートマシン
|
||||
* ステータスコード
|
||||
* 文字列
|
||||
* タグ
|
||||
* Web フレームワーク
|
||||
* ワイルドカード
|
||||
* 返す
|
||||
* 検証する
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
これはドキュメントで見られる(主に)技術用語の不完全かつ規範的でない一覧です。プロンプト設計者が、LLM がどの用語で手助けを必要としているかを把握するのに役立つかもしれません。例えば、良い翻訳を最適でない翻訳に戻してしまう場合や、あなたの言語での活用・格変化に問題がある場合などです。
|
||||
|
||||
`docs/de/llm-prompt.md` の「### List of English terms and their preferred German translations」の節を参照してください。
|
||||
|
||||
////
|
||||
3
docs/ja/docs/about/index.md
Normal file
3
docs/ja/docs/about/index.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 概要 { #about }
|
||||
|
||||
FastAPI の概要、その設計やインスピレーションなどについて解説します。🤓
|
||||
247
docs/ja/docs/advanced/additional-responses.md
Normal file
247
docs/ja/docs/advanced/additional-responses.md
Normal file
@@ -0,0 +1,247 @@
|
||||
# OpenAPI の追加レスポンス { #additional-responses-in-openapi }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これは比較的高度なトピックです。
|
||||
|
||||
FastAPI を使い始めたばかりであれば、これは不要かもしれません。
|
||||
|
||||
///
|
||||
|
||||
追加のステータスコード、メディアタイプ、説明などを伴う追加レスポンスを宣言できます。
|
||||
|
||||
それらの追加レスポンスは OpenAPI スキーマに含まれ、API ドキュメントにも表示されます。
|
||||
|
||||
ただし、それらの追加レスポンスについては、ステータスコードとコンテンツを指定して `JSONResponse` などの `Response` を直接返す必要があります。
|
||||
|
||||
## `model` を使った追加レスポンス { #additional-response-with-model }
|
||||
|
||||
*path operation デコレータ*に `responses` パラメータを渡せます。
|
||||
|
||||
これは `dict` を受け取り、キーは各レスポンスのステータスコード(例: `200`)、値は各レスポンスの情報を含む別の `dict` です。
|
||||
|
||||
それぞれのレスポンス `dict` には、`response_model` と同様に Pydantic モデルを格納する `model` キーを含められます。
|
||||
|
||||
FastAPI はそのモデルから JSON Schema を生成し、OpenAPI の適切な場所に含めます。
|
||||
|
||||
例えば、ステータスコード `404` と Pydantic モデル `Message` を持つ別のレスポンスを宣言するには、次のように書けます:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
`JSONResponse` を直接返す必要がある点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`model` キーは OpenAPI の一部ではありません。
|
||||
|
||||
FastAPI はそこから Pydantic モデルを取得して JSON Schema を生成し、適切な場所に配置します。
|
||||
|
||||
適切な場所は次のとおりです:
|
||||
|
||||
- `content` キーの中。これは値として別の JSON オブジェクト(`dict`)を持ち、その中に次が含まれます:
|
||||
- メディアタイプ(例: `application/json`)をキーとし、値としてさらに別の JSON オブジェクトを持ち、その中に次が含まれます:
|
||||
- `schema` キー。値としてモデル由来の JSON Schema を持ち、ここが正しい配置場所です。
|
||||
- FastAPI はここに、スキーマを直接埋め込む代わりに OpenAPI 内のグローバルな JSON Schema への参照を追加します。これにより、他のアプリケーションやクライアントがそれらの JSON Schema を直接利用し、より良いコード生成ツール等を提供できます。
|
||||
|
||||
///
|
||||
|
||||
この *path operation* のために OpenAPI に生成されるレスポンスは次のとおりです:
|
||||
|
||||
```JSON hl_lines="3-12"
|
||||
{
|
||||
"responses": {
|
||||
"404": {
|
||||
"description": "Additional Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Message"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
スキーマは OpenAPI スキーマ内の別の場所への参照になります:
|
||||
|
||||
```JSON hl_lines="4-16"
|
||||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
"Message": {
|
||||
"title": "Message",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"title": "Message",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": [
|
||||
"id",
|
||||
"value"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"title": "Id",
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"title": "Value",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": [
|
||||
"loc",
|
||||
"msg",
|
||||
"type"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"msg": {
|
||||
"title": "Message",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"title": "Error Type",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## メインのレスポンスに追加のメディアタイプ { #additional-media-types-for-the-main-response }
|
||||
|
||||
同じ `responses` パラメータを使って、同一のメインレスポンスに別のメディアタイプを追加できます。
|
||||
|
||||
例えば、`image/png` の追加メディアタイプを加え、あなたの *path operation* が JSON オブジェクト(メディアタイプ `application/json`)または PNG 画像を返せることを宣言できます:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
画像は `FileResponse` を使って直接返す必要がある点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`responses` パラメータで明示的に別のメディアタイプを指定しない限り、FastAPI はレスポンスがメインのレスポンスクラスと同じメディアタイプ(デフォルトは `application/json`)であるとみなします。
|
||||
|
||||
ただし、メディアタイプが `None` のカスタムレスポンスクラスを指定している場合、モデルが関連付けられた追加レスポンスには FastAPI は `application/json` を使用します。
|
||||
|
||||
///
|
||||
|
||||
## 情報の結合 { #combining-information }
|
||||
|
||||
`response_model`、`status_code`、`responses` パラメータなど、複数の場所からのレスポンス情報を組み合わせることもできます。
|
||||
|
||||
`response_model` を宣言し、デフォルトのステータスコード `200`(必要なら任意のコード)を使い、その同じレスポンスに対する追加情報を `responses` で OpenAPI スキーマに直接記述できます。
|
||||
|
||||
FastAPI は `responses` にある追加情報を保持し、モデルの JSON Schema と結合します。
|
||||
|
||||
例えば、Pydantic モデルを用い、独自の `description` を持つステータスコード `404` のレスポンスを宣言できます。
|
||||
|
||||
さらに、`response_model` を使うステータスコード `200` のレスポンスに独自の `example` を含めることもできます:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
|
||||
|
||||
これらはすべて結合されて OpenAPI に含まれ、API ドキュメントに表示されます:
|
||||
|
||||
<img src="/img/tutorial/additional-responses/image01.png">
|
||||
|
||||
## 事前定義レスポンスとカスタムの組み合わせ { #combine-predefined-responses-and-custom-ones }
|
||||
|
||||
多くの *path operations* に適用できる事前定義のレスポンスを用意しつつ、各 *path operation* ごとに必要なカスタムレスポンスと組み合わせたい場合があります。
|
||||
|
||||
そのような場合、Python の `**dict_to_unpack` による `dict` の「アンパック」テクニックを使えます:
|
||||
|
||||
```Python
|
||||
old_dict = {
|
||||
"old key": "old value",
|
||||
"second old key": "second old value",
|
||||
}
|
||||
new_dict = {**old_dict, "new key": "new value"}
|
||||
```
|
||||
|
||||
ここでは、`new_dict` には `old_dict` のすべてのキーと値に加え、新しいキーと値が含まれます:
|
||||
|
||||
```Python
|
||||
{
|
||||
"old key": "old value",
|
||||
"second old key": "second old value",
|
||||
"new key": "new value",
|
||||
}
|
||||
```
|
||||
|
||||
このテクニックを使うと、*path operations* で事前定義レスポンスを再利用し、さらにカスタムのレスポンスを組み合わせられます。
|
||||
|
||||
例えば:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
|
||||
|
||||
## OpenAPI レスポンスの詳細 { #more-information-about-openapi-responses }
|
||||
|
||||
レスポンスに正確に何を含められるかは、OpenAPI 仕様の次のセクションを参照してください:
|
||||
|
||||
- <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object" class="external-link" target="_blank">OpenAPI の Responses Object</a>。ここには `Response Object` が含まれます。
|
||||
- <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object" class="external-link" target="_blank">OpenAPI の Response Object</a>。`responses` パラメータ内の各レスポンスに、ここで定義されている要素を直接含められます。`description`、`headers`、`content`(ここで異なるメディアタイプや JSON Schema を宣言します)、`links` など。
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
|
||||
|
||||
/// warning | 注意
|
||||
/// warning
|
||||
|
||||
上の例のように `Response` を直接返すと、それはそのまま返されます。
|
||||
|
||||
@@ -38,4 +38,4 @@
|
||||
|
||||
追加のステータスコードとレスポンスを直接返す場合、それらは OpenAPI スキーマ(API ドキュメント)には含まれません。FastAPI には、事前に何が返されるかを知る方法がないからです。
|
||||
|
||||
しかし、[Additional Responses](additional-responses.md){.internal-link target=_blank} を使ってコード内にドキュメント化できます。
|
||||
しかし、[追加のレスポンス](additional-responses.md){.internal-link target=_blank} を使ってコード内にドキュメント化できます。
|
||||
|
||||
163
docs/ja/docs/advanced/advanced-dependencies.md
Normal file
163
docs/ja/docs/advanced/advanced-dependencies.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# 高度な依存関係 { #advanced-dependencies }
|
||||
|
||||
## パラメータ化された依存関係 { #parameterized-dependencies }
|
||||
|
||||
これまで見てきた依存関係は、固定の関数またはクラスでした。
|
||||
|
||||
しかし、多くの異なる関数やクラスを宣言せずに、その依存関係にパラメータを設定したい場合があります。
|
||||
|
||||
たとえば、クエリパラメータ `q` に、ある固定の内容が含まれているかを検査する依存関係が欲しいとします。
|
||||
|
||||
ただし、その固定の内容はパラメータ化できるようにしたいです。
|
||||
|
||||
## "callable" なインスタンス { #a-callable-instance }
|
||||
|
||||
Python には、クラスのインスタンスを "callable" にする方法があります。
|
||||
|
||||
クラス自体(これはすでに callable です)ではなく、そのクラスのインスタンスです。
|
||||
|
||||
そのためには、`__call__` メソッドを宣言します:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
|
||||
|
||||
この場合、この `__call__` が、**FastAPI** が追加のパラメータやサブ依存関係を確認するために使うものになり、後であなたの *path operation 関数* のパラメータに値を渡すために呼び出されるものになります。
|
||||
|
||||
## インスタンスのパラメータ化 { #parameterize-the-instance }
|
||||
|
||||
そして、`__init__` を使って、依存関係を「パラメータ化」するために利用できるインスタンスのパラメータを宣言できます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
|
||||
|
||||
この場合、**FastAPI** は `__init__` に触れたり気にかけたりすることはありません。私たちがコード内で直接使います。
|
||||
|
||||
## インスタンスの作成 { #create-an-instance }
|
||||
|
||||
このクラスのインスタンスは次のように作成できます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
|
||||
|
||||
このようにして依存関係を「パラメータ化」できます。いまや `"bar"` が属性 `checker.fixed_content` として中に保持されています。
|
||||
|
||||
## インスタンスを依存関係として使う { #use-the-instance-as-a-dependency }
|
||||
|
||||
その後、`Depends(FixedContentQueryChecker)` の代わりに `Depends(checker)` でこの `checker` を使えます。依存関係はクラスそのものではなく、インスタンスである `checker` だからです。
|
||||
|
||||
依存関係を解決するとき、**FastAPI** はこの `checker` を次のように呼び出します:
|
||||
|
||||
```Python
|
||||
checker(q="somequery")
|
||||
```
|
||||
|
||||
...そして、その戻り値を *path operation 関数* 内の依存関係の値として、パラメータ `fixed_content_included` に渡します:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ここまでの内容は回りくどく感じられるかもしれません。まだどのように役立つかが明確でないかもしれません。
|
||||
|
||||
これらの例は意図的に単純ですが、仕組みを示しています。
|
||||
|
||||
セキュリティの章では、同じやり方で実装されたユーティリティ関数があります。
|
||||
|
||||
ここまでを理解できていれば、そうしたセキュリティ用ユーティリティが内部でどのように動いているかも理解できています。
|
||||
|
||||
///
|
||||
|
||||
## `yield`、`HTTPException`、`except` とバックグラウンドタスクを伴う依存関係 { #dependencies-with-yield-httpexception-except-and-background-tasks }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これらの技術的詳細は、ほとんどの場合は不要です。
|
||||
|
||||
主に、0.121.0 より前の FastAPI アプリケーションがあり、`yield` を使う依存関係で問題が発生している場合に有用です。
|
||||
|
||||
///
|
||||
|
||||
`yield` を使う依存関係は、さまざまなユースケースに対応し、いくつかの問題を修正するために時間とともに進化してきました。ここでは変更点の概要を説明します。
|
||||
|
||||
### `yield` と `scope` を伴う依存関係 { #dependencies-with-yield-and-scope }
|
||||
|
||||
バージョン 0.121.0 で、`yield` を使う依存関係に対して `Depends(scope="function")` がサポートされました。
|
||||
|
||||
`Depends(scope="function")` を使うと、`yield` の後の終了コードは、クライアントへレスポンスが返される前、*path operation 関数* が終了した直後に実行されます。
|
||||
|
||||
そして、`Depends(scope="request")`(デフォルト)を使う場合、`yield` の後の終了コードはレスポンス送信後に実行されます。
|
||||
|
||||
詳しくはドキュメント「[`yield` を使う依存関係 - 早期終了と `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope)」を参照してください。
|
||||
|
||||
### `yield` と `StreamingResponse` を伴う依存関係、技術詳細 { #dependencies-with-yield-and-streamingresponse-technical-details }
|
||||
|
||||
FastAPI 0.118.0 より前では、`yield` を使う依存関係を使用すると、*path operation 関数* が戻ってからレスポンス送信直前に終了コードが実行されていました。
|
||||
|
||||
これは、レスポンスがネットワーク上を移動するのを待っている間に、不要にリソースを保持しないようにする意図でした。
|
||||
|
||||
この変更により、`StreamingResponse` を返す場合、`yield` を持つ依存関係の終了コードはすでに実行されていることになりました。
|
||||
|
||||
たとえば、`yield` を持つ依存関係の中でデータベースセッションを持っていた場合、`StreamingResponse` はデータをストリーミングしている間にそのセッションを使えません。というのも、`yield` の後の終了コードでそのセッションがすでにクローズされているからです。
|
||||
|
||||
この挙動は 0.118.0 で元に戻され、`yield` の後の終了コードはレスポンス送信後に実行されるようになりました。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
以下で見るように、これはバージョン 0.106.0 より前の挙動ととても似ていますが、いくつかのコーナーケースに対する改良とバグ修正が含まれています。
|
||||
|
||||
///
|
||||
|
||||
#### 早期終了コードのユースケース { #use-cases-with-early-exit-code }
|
||||
|
||||
特定の条件では、レスポンス送信前に `yield` を持つ依存関係の終了コードを実行する、古い挙動の恩恵を受けられるユースケースがあります。
|
||||
|
||||
例えば、`yield` を持つ依存関係でデータベースセッションを使ってユーザ検証だけを行い、その後は *path operation 関数* 内ではそのデータベースセッションを一切使わない、かつレスポンス送信に長い時間がかかる(例えばデータをゆっくり送る `StreamingResponse`)が、何らかの理由でデータベースは使わない、というケースです。
|
||||
|
||||
この場合、レスポンスの送信が終わるまでデータベースセッションが保持されますが、使わないのであれば保持する必要はありません。
|
||||
|
||||
次のようになります:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py *}
|
||||
|
||||
終了コード、すなわち `Session` の自動クローズは:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
|
||||
|
||||
...の部分で定義されており、遅いデータ送信が終わった後に実行されます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
|
||||
|
||||
しかし、`generate_stream()` はデータベースセッションを使わないため、レスポンス送信中にセッションを開いたままにしておく必要は実際にはありません。
|
||||
|
||||
SQLModel(または SQLAlchemy)でこの特定のユースケースがある場合は、不要になった時点でセッションを明示的にクローズできます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}
|
||||
|
||||
このようにすると、セッションはデータベース接続を解放するため、他のリクエストがそれを使えるようになります。
|
||||
|
||||
`yield` を持つ依存関係で早期終了が必要な別のユースケースがある場合は、あなたの具体的なユースケースと、なぜ `yield` を持つ依存関係の早期クローズが有益かを説明して、<a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussion の質問</a>を作成してください。
|
||||
|
||||
`yield` を持つ依存関係の早期クローズに納得できるユースケースがある場合は、早期クローズにオプトインする新しい方法を追加することを検討します。
|
||||
|
||||
### `yield` と `except` を伴う依存関係、技術詳細 { #dependencies-with-yield-and-except-technical-details }
|
||||
|
||||
FastAPI 0.110.0 より前では、`yield` を持つ依存関係を使い、その依存関係内で `except` によって例外を捕捉し、再度その例外を送出しなかった場合でも、その例外は自動的に送出(フォワード)され、任意の例外ハンドラまたは内部サーバエラーハンドラに渡されていました。
|
||||
|
||||
これは、ハンドラのないフォワードされた例外(内部サーバエラー)による未処理のメモリ消費を修正し、通常の Python コードの挙動と一貫性を持たせるため、バージョン 0.110.0 で変更されました。
|
||||
|
||||
### バックグラウンドタスクと `yield` を伴う依存関係、技術詳細 { #background-tasks-and-dependencies-with-yield-technical-details }
|
||||
|
||||
FastAPI 0.106.0 より前では、`yield` の後で例外を送出することはできませんでした。`yield` を持つ依存関係の終了コードはレスポンス送信「後」に実行されるため、[例外ハンドラ](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} はすでに実行済みでした。
|
||||
|
||||
これは主に、依存関係が "yield" した同じオブジェクトをバックグラウンドタスク内で利用できるようにするための設計でした。終了コードはバックグラウンドタスク完了後に実行されるからです。
|
||||
|
||||
これは、レスポンスがネットワーク上を移動するのを待っている間にリソースを保持しないようにする意図で、FastAPI 0.106.0 で変更されました。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
加えて、バックグラウンドタスクは通常、独立したロジックの集合であり、(例えば専用のデータベース接続など)それ自身のリソースで個別に扱うべきです。
|
||||
|
||||
そのため、このやり方の方がコードはおそらくよりクリーンになります。
|
||||
|
||||
///
|
||||
|
||||
この挙動に依存していた場合は、バックグラウンドタスク用のリソースをバックグラウンドタスク内部で作成し、`yield` を持つ依存関係のリソースに依存しないデータだけを内部で使用するようにしてください。
|
||||
|
||||
例えば、同じデータベースセッションを使うのではなく、バックグラウンドタスク内で新しいデータベースセッションを作成し、この新しいセッションでデータベースからオブジェクトを取得します。そして、バックグラウンドタスク関数の引数としてデータベースのオブジェクト自体を渡すのではなく、そのオブジェクトの ID を渡し、バックグラウンドタスク関数内でもう一度そのオブジェクトを取得します。
|
||||
61
docs/ja/docs/advanced/advanced-python-types.md
Normal file
61
docs/ja/docs/advanced/advanced-python-types.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# 高度な Python の型 { #advanced-python-types }
|
||||
|
||||
Python の型を扱うときに役立つ追加のアイデアをいくつか紹介します。
|
||||
|
||||
## `Union` または `Optional` の利用 { #using-union-or-optional }
|
||||
|
||||
何らかの理由で `|` が使えない場合、たとえば型アノテーションではなく `response_model=` のような場所では、縦棒(`|`)の代わりに `typing` の `Union` を使えます。
|
||||
|
||||
例えば、`str` または `None` になり得ることを宣言できます:
|
||||
|
||||
```python
|
||||
from typing import Union
|
||||
|
||||
|
||||
def say_hi(name: Union[str, None]):
|
||||
print(f"Hi {name}!")
|
||||
```
|
||||
|
||||
`typing` には、`None` を取り得ることを宣言するための短縮形として `Optional` もあります。
|
||||
|
||||
ここからは私のとても主観的な提案です:
|
||||
|
||||
- 🚨 `Optional[SomeType]` の使用は避けましょう
|
||||
- 代わりに ✨ **`Union[SomeType, None]` を使いましょう** ✨。
|
||||
|
||||
どちらも等価で内部的には同一ですが、「optional(任意)」という語が値が任意だと誤解させやすく、実際の意味は「`None` を取り得る」であり、任意ではなく依然として必須である場合でもそうです。そのため `Optional` より `Union` を勧めます。
|
||||
|
||||
`Union[SomeType, None]` の方が意味がより明確だと思います。
|
||||
|
||||
これは用語や名前付けの話に過ぎませんが、その言葉があなたやチームメイトのコードの捉え方に影響します。
|
||||
|
||||
例として次の関数を見てみましょう:
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def say_hi(name: Optional[str]):
|
||||
print(f"Hey {name}!")
|
||||
```
|
||||
|
||||
パラメータ `name` は `Optional[str]` と定義されていますが、任意ではありません。このパラメータなしで関数を呼び出すことはできません:
|
||||
|
||||
```Python
|
||||
say_hi() # あっ、これはエラーになります!😱
|
||||
```
|
||||
|
||||
`name` パラメータにはデフォルト値がないため、依然として必須(任意ではない)です。ただし、`name` は値として `None` を受け付けます:
|
||||
|
||||
```Python
|
||||
say_hi(name=None) # これは動作します。None は有効です 🎉
|
||||
```
|
||||
|
||||
朗報として、多くの場合は単純に `|` を使って型の Union を定義できます:
|
||||
|
||||
```python
|
||||
def say_hi(name: str | None):
|
||||
print(f"Hey {name}!")
|
||||
```
|
||||
|
||||
したがって、通常は `Optional` や `Union` といった名前を気にする必要はありません。😎
|
||||
99
docs/ja/docs/advanced/async-tests.md
Normal file
99
docs/ja/docs/advanced/async-tests.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# 非同期テスト { #async-tests }
|
||||
|
||||
これまでに、提供されている `TestClient` を使って **FastAPI** アプリケーションをテストする方法を見てきました。ここまでは、`async` 関数を使わない同期テストのみでした。
|
||||
|
||||
テストで非同期関数を使えると、たとえばデータベースへ非同期にクエリする場合などに便利です。非同期データベースライブラリを使いながら、FastAPI アプリにリクエストを送り、その後バックエンドが正しいデータをデータベースに書き込めたかを検証したい、といったケースを想像してください。
|
||||
|
||||
その方法を見ていきます。
|
||||
|
||||
## pytest.mark.anyio { #pytest-mark-anyio }
|
||||
|
||||
テスト内で非同期関数を呼び出したい場合、テスト関数自体も非同期である必要があります。AnyIO はこれを実現するための便利なプラグインを提供しており、特定のテスト関数を非同期で呼び出すことを指定できます。
|
||||
|
||||
## HTTPX { #httpx }
|
||||
|
||||
**FastAPI** アプリケーションが通常の `def` 関数を使っていても、その内側は依然として `async` アプリケーションです。
|
||||
|
||||
`TestClient` は、標準の pytest を使って通常の `def` のテスト関数から非同期の FastAPI アプリを呼び出すための「おまじない」を内部で行います。しかし、その「おまじない」はテスト関数自体が非同期の場合には機能しません。テストを非同期で実行すると、テスト関数内で `TestClient` は使えなくなります。
|
||||
|
||||
`TestClient` は <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> を基に作られており、幸いなことに API のテストには HTTPX を直接利用できます。
|
||||
|
||||
## 例 { #example }
|
||||
|
||||
簡単な例として、[大きなアプリケーション](../tutorial/bigger-applications.md){.internal-link target=_blank} と [テスト](../tutorial/testing.md){.internal-link target=_blank} で説明したものに似たファイル構成を考えます:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ └── test_main.py
|
||||
```
|
||||
|
||||
`main.py` は次のようになります:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/main.py *}
|
||||
|
||||
`test_main.py` は `main.py` のテストを持ち、次のようになります:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
|
||||
|
||||
## 実行 { #run-it }
|
||||
|
||||
テストはいつも通り次で実行できます:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pytest
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## 詳細 { #in-detail }
|
||||
|
||||
マーカー `@pytest.mark.anyio` は、このテスト関数を非同期で呼び出すべきであることを pytest に伝えます:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`TestClient` を使っていたときと異なり、テスト関数は `def` ではなく `async def` になっている点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
次に、アプリを渡して `AsyncClient` を作成し、`await` を使って非同期リクエストを送信できます。
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
|
||||
|
||||
これは次と同等です:
|
||||
|
||||
```Python
|
||||
response = client.get('/')
|
||||
```
|
||||
|
||||
...これまでは `TestClient` でリクエストを送っていました。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
新しい `AsyncClient` では async/await を使っている点に注意してください。リクエストは非同期です。
|
||||
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
アプリケーションが lifespan イベントに依存している場合、`AsyncClient` はそれらのイベントをトリガーしません。確実にトリガーするには、<a href="https://github.com/florimondmanca/asgi-lifespan#usage" class="external-link" target="_blank">florimondmanca/asgi-lifespan</a> の `LifespanManager` を使用してください。
|
||||
|
||||
///
|
||||
|
||||
## その他の非同期関数呼び出し { #other-asynchronous-function-calls }
|
||||
|
||||
テスト関数が非同期になったので、FastAPI アプリへのリクエスト送信以外の `async` 関数も、コードの他の場所と同様に呼び出して(`await` して)使えます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
テストに非同期関数呼び出しを統合した際に(例: <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB の MotorClient</a> 使用時)、`RuntimeError: Task attached to a different loop` に遭遇した場合は、イベントループを必要とするオブジェクトは非同期関数内でのみインスタンス化するようにしてください。例えば `@app.on_event("startup")` コールバック内で行います。
|
||||
|
||||
///
|
||||
466
docs/ja/docs/advanced/behind-a-proxy.md
Normal file
466
docs/ja/docs/advanced/behind-a-proxy.md
Normal file
@@ -0,0 +1,466 @@
|
||||
# プロキシの背後 { #behind-a-proxy }
|
||||
|
||||
多くの状況で、FastAPI アプリの前段に **Traefik** や **Nginx** のような**プロキシ**を置きます。
|
||||
|
||||
これらのプロキシは HTTPS 証明書などの処理を担います。
|
||||
|
||||
## プロキシの転送ヘッダー { #proxy-forwarded-headers }
|
||||
|
||||
アプリケーションの前段にある **プロキシ** は通常、リクエストを **サーバー** に送る前に、そのリクエストがプロキシによって転送されたことを知らせるためのヘッダーを動的に付与し、使用中の元の(公開)URL(ドメインを含む)や HTTPS 使用などの情報を伝えます。
|
||||
|
||||
**サーバー** プログラム(例えば **FastAPI CLI** 経由の **Uvicorn**)はこれらのヘッダーを解釈し、その情報をアプリケーションに渡すことができます。
|
||||
|
||||
しかしセキュリティ上、サーバーは自分が信頼できるプロキシの背後にあると分からないため、これらのヘッダーを解釈しません。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
プロキシのヘッダーは次のとおりです:
|
||||
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
|
||||
|
||||
///
|
||||
|
||||
### プロキシ転送ヘッダーを有効化 { #enable-proxy-forwarded-headers }
|
||||
|
||||
FastAPI CLI を *CLI オプション* `--forwarded-allow-ips` 付きで起動し、転送ヘッダーを信頼して読んでよい IP アドレスを指定できます。
|
||||
|
||||
`--forwarded-allow-ips="*"` とすると、すべての送信元 IP を信頼します。
|
||||
|
||||
**サーバー** が信頼できる **プロキシ** の背後にあり、そのプロキシからのみ接続される場合、プロキシの IP を受け入れるようになります。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run --forwarded-allow-ips="*"
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### HTTPS を伴うリダイレクト { #redirects-with-https }
|
||||
|
||||
例えば、*path operation* `/items/` を定義しているとします:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
|
||||
|
||||
クライアントが `/items` にアクセスすると、既定では `/items/` にリダイレクトされます。
|
||||
|
||||
しかし、*CLI オプション* `--forwarded-allow-ips` を設定する前は、`http://localhost:8000/items/` にリダイレクトされる場合があります。
|
||||
|
||||
ですが、アプリケーションは `https://mysuperapp.com` で公開されており、`https://mysuperapp.com/items/` にリダイレクトされるべきかもしれません。
|
||||
|
||||
`--proxy-headers` を設定すると、FastAPI は正しい場所にリダイレクトできるようになります。😎
|
||||
|
||||
```
|
||||
https://mysuperapp.com/items/
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
HTTPS について詳しく知りたい場合は、[HTTPS について](../deployment/https.md){.internal-link target=_blank} を参照してください。
|
||||
|
||||
///
|
||||
|
||||
### プロキシ転送ヘッダーの仕組み { #how-proxy-forwarded-headers-work }
|
||||
|
||||
クライアントと **アプリケーションサーバー** の間で、**プロキシ** がどのように転送ヘッダーを追加するかを図示します:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Proxy as Proxy/Load Balancer
|
||||
participant Server as FastAPI Server
|
||||
|
||||
Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items
|
||||
|
||||
Note over Proxy: Proxy adds forwarded headers
|
||||
|
||||
Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items
|
||||
|
||||
Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)
|
||||
|
||||
Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs
|
||||
|
||||
Proxy->>Client: HTTPS Response
|
||||
```
|
||||
|
||||
**プロキシ** は元のクライアントリクエストを受け取り、**アプリケーションサーバー** に渡す前に特別な「転送」ヘッダー(`X-Forwarded-*`)を追加します。
|
||||
|
||||
これらのヘッダーは、通常は失われる元のリクエストの情報を保持します:
|
||||
|
||||
* **X-Forwarded-For**: 元のクライアントの IP アドレス
|
||||
* **X-Forwarded-Proto**: 元のプロトコル(`https`)
|
||||
* **X-Forwarded-Host**: 元のホスト(`mysuperapp.com`)
|
||||
|
||||
**FastAPI CLI** を `--forwarded-allow-ips` で設定すると、これらのヘッダーを信頼して使用し、たとえばリダイレクトで正しい URL を生成します。
|
||||
|
||||
## パスプレフィックスを削除するプロキシ { #proxy-with-a-stripped-path-prefix }
|
||||
|
||||
アプリケーションにパスプレフィックスを付与するプロキシを使う場合があります。
|
||||
|
||||
そのような場合は `root_path` でアプリケーションを設定できます。
|
||||
|
||||
`root_path` は(FastAPI が Starlette を通して基づいている)ASGI 仕様で提供されている仕組みです。
|
||||
|
||||
`root_path` はこの種のケースを扱うために使われます。
|
||||
|
||||
これはサブアプリケーションをマウントする際にも内部的に使用されます。
|
||||
|
||||
ここでいう「パスプレフィックスを削除するプロキシ」とは、コード上では `/app` というパスを宣言していても、その上にプロキシ層を追加して **FastAPI** アプリケーションを `/api/v1` のようなパスの下に配置することを指します。
|
||||
|
||||
この場合、元のパス `/app` は実際には `/api/v1/app` で提供されます。
|
||||
|
||||
すべてのコードは `/app` だけを前提に書かれているにもかかわらず、です。
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
|
||||
|
||||
そしてプロキシは、アプリサーバー(おそらく FastAPI CLI 経由の Uvicorn)に転送する前に、その場で **パスプレフィックス** を**「削除」**し、アプリケーション側には自分が `/app` で提供されているように見せかけます。これにより、コードのすべてを `/api/v1` のプレフィックス付きに書き換える必要がありません。
|
||||
|
||||
ここまでは通常どおりに動作します。
|
||||
|
||||
しかし、統合ドキュメント UI(フロントエンド)を開くと、OpenAPI スキーマを `/api/v1/openapi.json` ではなく `/openapi.json` から取得しようとします。
|
||||
|
||||
そのため、フロントエンド(ブラウザで動作)は `/openapi.json` にアクセスしようとして、OpenAPI スキーマを取得できません。
|
||||
|
||||
このアプリには `/api/v1` のパスプレフィックスを付与するプロキシがあるため、フロントエンドは `/api/v1/openapi.json` から取得する必要があります。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
|
||||
browser("Browser")
|
||||
proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
|
||||
server["Server on http://127.0.0.1:8000/app"]
|
||||
|
||||
browser --> proxy
|
||||
proxy --> server
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
IP `0.0.0.0` は、そのマシン/サーバーで利用可能なすべての IP で待ち受けることを意味する表現として一般的に使われます。
|
||||
|
||||
///
|
||||
|
||||
ドキュメント UI では、この API の `server` が(プロキシの背後で)`/api/v1` にあることを宣言する OpenAPI スキーマも必要です。例えば:
|
||||
|
||||
```JSON hl_lines="4-8"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
// ほかの項目
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// ほかの項目
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
この例では「Proxy」は **Traefik** のようなもの、サーバーは **Uvicorn** と FastAPI CLI で FastAPI アプリケーションを実行しているものを想定しています。
|
||||
|
||||
### `root_path` の指定 { #providing-the-root-path }
|
||||
|
||||
これを実現するには、次のようにコマンドラインオプション `--root-path` を使用します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Hypercorn を使う場合も、同様に `--root-path` オプションがあります。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
このユースケース向けに、ASGI 仕様は `root_path` を定義しています。
|
||||
|
||||
そして `--root-path` コマンドラインオプションは、その `root_path` を提供します。
|
||||
|
||||
///
|
||||
|
||||
### 現在の `root_path` の確認 { #checking-the-current-root-path }
|
||||
|
||||
各リクエストでアプリケーションが使用している現在の `root_path` は取得できます。これは(ASGI 仕様の一部である)`scope` 辞書に含まれます。
|
||||
|
||||
ここではデモのため、メッセージに含めています。
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
|
||||
|
||||
そのうえで、次のように Uvicorn を起動すると:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
レスポンスは次のようになります:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
### FastAPI アプリでの `root_path` 設定 { #setting-the-root-path-in-the-fastapi-app }
|
||||
|
||||
あるいは、`--root-path` のようなコマンドラインオプションを渡せない場合は、FastAPI アプリ作成時にパラメータ `root_path` を設定できます:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
|
||||
|
||||
`FastAPI` に `root_path` を渡すのは、Uvicorn や Hypercorn にコマンドラインオプション `--root-path` を渡すのと同等です。
|
||||
|
||||
### `root_path` について { #about-root-path }
|
||||
|
||||
サーバー(Uvicorn)は、その `root_path` をアプリに渡す以外の用途では使用しない点に注意してください。
|
||||
|
||||
しかし、ブラウザで <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a> にアクセスすると、通常どおりのレスポンスが表示されます:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
つまり、`http://127.0.0.1:8000/api/v1/app` でアクセスされることは想定していません。
|
||||
|
||||
Uvicorn は、プロキシが `http://127.0.0.1:8000/app` にアクセスしてくることを想定しており、その上に追加の `/api/v1` プレフィックスを付けるのはプロキシの責務です。
|
||||
|
||||
## パスプレフィックスを削除するプロキシについて { #about-proxies-with-a-stripped-path-prefix }
|
||||
|
||||
パスプレフィックスを削除するプロキシは、設定方法の一例にすぎない点に注意してください。
|
||||
|
||||
多くの場合、プロキシはパスプレフィックスを削除しない設定が既定でしょう。
|
||||
|
||||
そのような場合(パスプレフィックスを削除しない場合)は、プロキシは `https://myawesomeapp.com` のようなアドレスで待ち受け、ブラウザが `https://myawesomeapp.com/api/v1/app` にアクセスし、サーバー(例: Uvicorn)が `http://127.0.0.1:8000` で待ち受けているなら、プロキシ(プレフィックスを削除しない)は同じパス `http://127.0.0.1:8000/api/v1/app` で Uvicorn にアクセスします。
|
||||
|
||||
## Traefik を使ったローカル検証 { #testing-locally-with-traefik }
|
||||
|
||||
<a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a> を使えば、パスプレフィックスを削除する構成をローカルで簡単に試せます。
|
||||
|
||||
<a href="https://github.com/containous/traefik/releases" class="external-link" target="_blank">Traefik をダウンロード</a> してください。単一バイナリなので、圧縮ファイルを展開して端末から直接実行できます。
|
||||
|
||||
次の内容で `traefik.toml` というファイルを作成します:
|
||||
|
||||
```TOML hl_lines="3"
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":9999"
|
||||
|
||||
[providers]
|
||||
[providers.file]
|
||||
filename = "routes.toml"
|
||||
```
|
||||
|
||||
これは Traefik にポート 9999 で待ち受け、別のファイル `routes.toml` を使用するよう指示します。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
標準の HTTP ポート 80 ではなく 9999 を使うのは、管理者(`sudo`)権限で実行する必要をなくすためです。
|
||||
|
||||
///
|
||||
|
||||
次に、その `routes.toml` ファイルを作成します:
|
||||
|
||||
```TOML hl_lines="5 12 20"
|
||||
[http]
|
||||
[http.middlewares]
|
||||
|
||||
[http.middlewares.api-stripprefix.stripPrefix]
|
||||
prefixes = ["/api/v1"]
|
||||
|
||||
[http.routers]
|
||||
|
||||
[http.routers.app-http]
|
||||
entryPoints = ["http"]
|
||||
service = "app"
|
||||
rule = "PathPrefix(`/api/v1`)"
|
||||
middlewares = ["api-stripprefix"]
|
||||
|
||||
[http.services]
|
||||
|
||||
[http.services.app]
|
||||
[http.services.app.loadBalancer]
|
||||
[[http.services.app.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:8000"
|
||||
```
|
||||
|
||||
このファイルは Traefik に `/api/v1` のパスプレフィックスを使うよう設定します。
|
||||
|
||||
そして Traefik は、`http://127.0.0.1:8000` で動作している Uvicorn へリクエストを転送します。
|
||||
|
||||
では Traefik を起動します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ ./traefik --configFile=traefik.toml
|
||||
|
||||
INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
次に、`--root-path` オプションを指定してアプリを起動します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### レスポンスの確認 { #check-the-responses }
|
||||
|
||||
ここで、Uvicorn のポートの URL <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a> にアクセスすると、通常どおりのレスポンスが表示されます:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`http://127.0.0.1:8000/app` にアクセスしているにもかかわらず、オプション `--root-path` から取得した `root_path` が `/api/v1` と表示されている点に注目してください。
|
||||
|
||||
///
|
||||
|
||||
次に、Traefik のポートでプレフィックス付きの URL <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/app</a> を開きます。
|
||||
|
||||
同じレスポンスが得られます:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
ただし今回は、プロキシが付与したプレフィックス `/api/v1` の付いた URL です。
|
||||
|
||||
もちろん、ここでの想定は全員がプロキシ経由でアプリにアクセスすることです。したがって、パスプレフィックス `/api/v1` のある版が「正しい」アクセス方法になります。
|
||||
|
||||
一方、プレフィックスのない版(`http://127.0.0.1:8000/app`。Uvicorn が直接提供)は、_プロキシ_(Traefik)専用の接続先になります。
|
||||
|
||||
これにより、プロキシ(Traefik)がパスプレフィックスをどのように用い、サーバー(Uvicorn)が `--root-path` の `root_path` をどのように利用するかが分かります。
|
||||
|
||||
### ドキュメント UI の確認 { #check-the-docs-ui }
|
||||
|
||||
ここがポイントです。✨
|
||||
|
||||
「公式な」アクセス方法は、定義したパスプレフィックス付きのプロキシ経由です。したがって想定どおり、プレフィックスなしの URL で Uvicorn が直接提供するドキュメント UI にアクセスすると動作しません。プロキシ経由でアクセスされることを前提としているためです。
|
||||
|
||||
<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> を確認してください:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image01.png">
|
||||
|
||||
しかし、プロキシ(ポート `9999`)を使った「公式」URL `/api/v1/docs` でドキュメント UI にアクセスすると、正しく動作します!🎉
|
||||
|
||||
<a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a> を確認してください:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image02.png">
|
||||
|
||||
ねらいどおりです。✔️
|
||||
|
||||
これは、FastAPI が `root_path` を使って、OpenAPI の既定の `server` を `root_path` の URL で生成するためです。
|
||||
|
||||
## 追加のサーバー { #additional-servers }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これは高度なユースケースです。読み飛ばしても構いません。
|
||||
|
||||
///
|
||||
|
||||
既定では、**FastAPI** は OpenAPI スキーマ内に `root_path` の URL を持つ `server` を作成します。
|
||||
|
||||
しかし、ステージングと本番の両方と同じドキュメント UI で対話させたい場合など、別の `servers` を指定することもできます。
|
||||
|
||||
カスタムの `servers` リストを渡していて、かつ `root_path`(API がプロキシの背後にあるため)が設定されている場合、**FastAPI** はこの `root_path` を用いた「server」をリストの先頭に挿入します。
|
||||
|
||||
例えば:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
|
||||
|
||||
次のような OpenAPI スキーマが生成されます:
|
||||
|
||||
```JSON hl_lines="5-7"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
// ほかの項目
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
},
|
||||
{
|
||||
"url": "https://stag.example.com",
|
||||
"description": "Staging environment"
|
||||
},
|
||||
{
|
||||
"url": "https://prod.example.com",
|
||||
"description": "Production environment"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// ほかの項目
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`root_path` から取得した `url` 値 `/api/v1` を持つ server が自動生成されている点に注目してください。
|
||||
|
||||
///
|
||||
|
||||
ドキュメント UI(<a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>)では次のように表示されます:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image03.png">
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ドキュメント UI は、選択した server と対話します。
|
||||
|
||||
///
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
OpenAPI 仕様の `servers` プロパティは任意です。
|
||||
|
||||
`servers` パラメータを指定せず、かつ `root_path` が `/` の場合、生成される OpenAPI スキーマからは `servers` プロパティが既定で完全に省略されます。これは、`url` が `/` の server が 1 つあるのと同等です。
|
||||
|
||||
///
|
||||
|
||||
### `root_path` 由来の自動 server を無効化 { #disable-automatic-server-from-root-path }
|
||||
|
||||
`root_path` を用いた自動的な server を **FastAPI** に含めてほしくない場合は、パラメータ `root_path_in_servers=False` を使用します:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
|
||||
|
||||
すると、OpenAPI スキーマには含まれません。
|
||||
|
||||
## サブアプリケーションのマウント { #mounting-a-sub-application }
|
||||
|
||||
`root_path` を伴うプロキシを使用しつつサブアプリケーションをマウントする必要がある場合でも([サブアプリケーション - マウント](sub-applications.md){.internal-link target=_blank} 参照)、通常どおりに行えます。
|
||||
|
||||
FastAPI は内部で `root_path` を適切に扱うため、そのまま動作します。✨
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
しかし、返そうとしているコンテンツが **JSONでシリアライズ可能**であることが確実なら、それを直接レスポンスクラスに渡して、FastAPIがレスポンスクラスへ渡す前に返却コンテンツを `jsonable_encoder` に通すことで発生する追加のオーバーヘッドを回避できます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
* `HTMLResponse` をインポートする。
|
||||
* *path operation デコレータ* のパラメータ `response_class` に `HTMLResponse` を渡す。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
上記と同じ例において、 `HTMLResponse` を返すと、このようになります:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
|
||||
{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
|
||||
例えば、このようになります:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
|
||||
{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
|
||||
|
||||
この例では、関数 `generate_html_response()` は、`str` のHTMLを返すのではなく、`Response` を生成して返しています。
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
|
||||
FastAPI(実際にはStarlette)は自動的にContent-Lengthヘッダーを含みます。また、`media_type` に基づいたContent-Typeヘッダーを含み、テキストタイプのためにcharsetを追加します。
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
|
||||
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
|
||||
|
||||
### `HTMLResponse` { #htmlresponse }
|
||||
|
||||
@@ -146,7 +146,7 @@ FastAPI(実際にはStarlette)は自動的にContent-Lengthヘッダーを
|
||||
|
||||
テキストやバイトを受け取り、プレーンテキストのレスポンスを返します。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
|
||||
|
||||
### `JSONResponse` { #jsonresponse }
|
||||
|
||||
@@ -180,7 +180,7 @@ FastAPI(実際にはStarlette)は自動的にContent-Lengthヘッダーを
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -194,13 +194,13 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
|
||||
|
||||
`RedirectResponse` を直接返せます:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
|
||||
|
||||
---
|
||||
|
||||
または、`response_class` パラメータで使用できます:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
|
||||
|
||||
その場合、*path operation*関数からURLを直接返せます。
|
||||
|
||||
@@ -210,13 +210,13 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
|
||||
|
||||
また、`status_code` パラメータを `response_class` パラメータと組み合わせて使うこともできます:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
|
||||
|
||||
### `StreamingResponse` { #streamingresponse }
|
||||
|
||||
非同期ジェネレータ、または通常のジェネレータ/イテレータを受け取り、レスポンスボディをストリームします。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
|
||||
{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
|
||||
|
||||
#### ファイルライクオブジェクトで `StreamingResponse` を使う { #using-streamingresponse-with-file-like-objects }
|
||||
|
||||
@@ -226,7 +226,7 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
|
||||
|
||||
これにはクラウドストレージとの連携、映像処理など、多くのライブラリが含まれます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
|
||||
{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
|
||||
|
||||
1. これはジェネレータ関数です。内部に `yield` 文を含むため「ジェネレータ関数」です。
|
||||
2. `with` ブロックを使うことで、ジェネレータ関数が終わった後(つまりレスポンスの送信が完了した後)にfile-likeオブジェクトが確実にクローズされるようにします。
|
||||
@@ -255,11 +255,11 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
|
||||
|
||||
ファイルレスポンスには、適切な `Content-Length`、`Last-Modified`、`ETag` ヘッダーが含まれます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
|
||||
{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
|
||||
|
||||
`response_class` パラメータを使うこともできます:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
|
||||
{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
|
||||
|
||||
この場合、*path operation*関数からファイルパスを直接返せます。
|
||||
|
||||
@@ -273,7 +273,7 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
|
||||
|
||||
`CustomORJSONResponse` を作れます。主に必要なのは、コンテンツを `bytes` として返す `Response.render(content)` メソッドを作ることです:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
|
||||
{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
|
||||
|
||||
これまでは次のように返していたものが:
|
||||
|
||||
@@ -299,7 +299,7 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
|
||||
|
||||
以下の例では、**FastAPI** はすべての*path operation*で、`JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして使います。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
|
||||
{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
|
||||
95
docs/ja/docs/advanced/dataclasses.md
Normal file
95
docs/ja/docs/advanced/dataclasses.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# Dataclasses の使用 { #using-dataclasses }
|
||||
|
||||
FastAPI は **Pydantic** の上に構築されており、これまでにリクエストやレスポンスを宣言するために Pydantic モデルを使う方法を紹介してきました。
|
||||
|
||||
しかし FastAPI は、同様の方法で <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> もサポートします:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
|
||||
|
||||
これは **Pydantic** によって引き続きサポートされています。Pydantic には <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">`dataclasses` の内部サポート</a> があるためです。
|
||||
|
||||
そのため、上記のように明示的に Pydantic を使っていないコードでも、FastAPI は標準の dataclass を Pydantic 独自の dataclass に変換するために Pydantic を使用しています。
|
||||
|
||||
そして当然ながら、次の点も同様にサポートされます:
|
||||
|
||||
- データ検証
|
||||
- データのシリアライズ
|
||||
- データのドキュメント化 など
|
||||
|
||||
これは Pydantic モデルの場合と同じように動作します。内部的にも同様に Pydantic を使って実現されています。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
dataclasses は、Pydantic モデルができることをすべては行えない点に留意してください。
|
||||
|
||||
そのため、Pydantic モデルを使う必要がある場合もあります。
|
||||
|
||||
しかし既存の dataclass が多数あるなら、FastAPI で Web API を構築する際にそれらを活用するちょっとしたテクニックになります。🤓
|
||||
|
||||
///
|
||||
|
||||
## `response_model` での dataclasses { #dataclasses-in-response-model }
|
||||
|
||||
`response_model` パラメータでも `dataclasses` を使用できます:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
|
||||
|
||||
dataclass は自動的に Pydantic の dataclass に変換されます。
|
||||
|
||||
このため、そのスキーマは API ドキュメントの UI に表示されます:
|
||||
|
||||
<img src="/img/tutorial/dataclasses/image01.png">
|
||||
|
||||
## ネストしたデータ構造での dataclasses { #dataclasses-in-nested-data-structures }
|
||||
|
||||
`dataclasses` を他の型注釈と組み合わせて、ネストしたデータ構造を作成できます。
|
||||
|
||||
場合によっては、自動生成された API ドキュメントでエラーが発生するなどの理由で、Pydantic 版の `dataclasses` を使う必要があるかもしれません。
|
||||
|
||||
その場合は、標準の `dataclasses` を `pydantic.dataclasses` に置き換えるだけで済みます。これはドロップイン置換です:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
|
||||
|
||||
1. 依然として標準の `dataclasses` から `field` をインポートします。
|
||||
|
||||
2. `pydantic.dataclasses` は `dataclasses` のドロップイン置換です。
|
||||
|
||||
3. `Author` dataclass は `Item` dataclass のリストを含みます。
|
||||
|
||||
4. `Author` dataclass を `response_model` パラメータとして使用しています。
|
||||
|
||||
5. リクエストボディとしての dataclass と併せて、他の標準の型注釈を使用できます。
|
||||
|
||||
この例では、`Item` dataclass のリストです。
|
||||
|
||||
6. ここでは、dataclass のリストである `items` を含む辞書を返しています。
|
||||
|
||||
FastAPI はデータを JSON に <dfn title="送信可能な形式にデータを変換すること">シリアライズ</dfn> できます。
|
||||
|
||||
7. ここでは `response_model` に `Author` dataclass のリストという型注釈を使用しています。
|
||||
|
||||
このように、`dataclasses` は標準の型注釈と組み合わせられます。
|
||||
|
||||
8. この *path operation 関数* は、`async def` ではなく通常の `def` を使用しています。
|
||||
|
||||
いつもどおり、FastAPI では必要に応じて `def` と `async def` を組み合わせられます。
|
||||
|
||||
どちらをいつ使うかの復習が必要な場合は、[`async` と `await`](../async.md#in-a-hurry){.internal-link target=_blank} に関するドキュメントの _"In a hurry?"_ セクションを参照してください。
|
||||
|
||||
9. この *path operation 関数* は(可能ではありますが)dataclass 自体は返さず、内部データを持つ辞書のリストを返しています。
|
||||
|
||||
FastAPI は dataclass を含む `response_model` パラメータを使ってレスポンスを変換します。
|
||||
|
||||
`dataclasses` は他の型注釈と多様な組み合わせが可能で、複雑なデータ構造を構成できます。
|
||||
|
||||
上記のコード内コメントのヒントを参照して、より具体的な詳細を確認してください。
|
||||
|
||||
## さらに学ぶ { #learn-more }
|
||||
|
||||
`dataclasses` を他の Pydantic モデルと組み合わせたり、継承したり、自分のモデルに含めたりもできます。
|
||||
|
||||
詳しくは、<a href="https://docs.pydantic.dev/latest/concepts/dataclasses/" class="external-link" target="_blank">dataclasses に関する Pydantic ドキュメント</a> を参照してください。
|
||||
|
||||
## バージョン { #version }
|
||||
|
||||
これは FastAPI バージョン `0.67.0` 以降で利用可能です。🔖
|
||||
165
docs/ja/docs/advanced/events.md
Normal file
165
docs/ja/docs/advanced/events.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# Lifespan イベント { #lifespan-events }
|
||||
|
||||
アプリケーションが起動する前に一度だけ実行すべきロジック(コード)を定義できます。これは、アプリケーションがリクエストを受け取り始める前に、そのコードが一度だけ実行される、という意味です。
|
||||
|
||||
同様に、アプリケーションがシャットダウンするときに実行すべきロジック(コード)も定義できます。この場合、そのコードは、(多くのリクエストを処理した)後に一度だけ実行されます。
|
||||
|
||||
このコードは、アプリケーションがリクエストの受け付けを「開始」する前、そして処理を「終了」した直後に実行されるため、アプリケーションの全体の「Lifespan」(この「lifespan」という言葉はすぐ後で重要になります 😉)をカバーします。
|
||||
|
||||
これは、アプリ全体で使用し、リクエスト間で「共有」し、かつ後で「クリーンアップ」する必要があるような「リソース」をセットアップするのにとても便利です。たとえば、データベース接続プールや、共有の機械学習モデルの読み込みなどです。
|
||||
|
||||
## ユースケース { #use-case }
|
||||
|
||||
まずはユースケースの例から始めて、これをどのように解決するかを見ていきます。
|
||||
|
||||
リクエストを処理するために使用したい「機械学習モデル」がいくつかあると想像してください。🤖
|
||||
|
||||
同じモデルをリクエスト間で共有するので、リクエストごとやユーザーごとに別々のモデルを使うわけではありません。
|
||||
|
||||
モデルの読み込みにはディスクから大量のデータを読む必要があり、かなり時間がかかるかもしれません。したがって、リクエストごとに読み込みたくはありません。
|
||||
|
||||
モジュール/ファイルのトップレベルで読み込むこともできますが、その場合は、たとえ簡単な自動テストを実行するだけでも「モデルを読み込む」ことになり、そのモデルの読み込みを待つ必要があるため、独立したコード部分を走らせるだけのテストでも「遅く」なってしまいます。
|
||||
|
||||
これを解決しましょう。リクエストを処理する前にモデルを読み込みますが、コードがロードされている最中ではなく、アプリケーションがリクエストの受け付けを開始する直前だけにします。
|
||||
|
||||
## Lifespan { #lifespan }
|
||||
|
||||
この「起動時」と「シャットダウン時」のロジックは、`FastAPI` アプリの `lifespan` パラメータと「コンテキストマネージャ」(これが何かはすぐに示します)を使って定義できます。
|
||||
|
||||
まずは例を見てから、詳細を説明します。
|
||||
|
||||
次のように、`yield` を使う非同期関数 `lifespan()` を作成します:
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
|
||||
|
||||
ここでは、`yield` の前で機械学習モデルの辞書に(ダミーの)モデル関数を入れることで、高コストな「起動時」のモデル読み込みをシミュレーションしています。このコードは、アプリケーションがリクエストを「受け付け始める前」に、すなわち起動時に実行されます。
|
||||
|
||||
そして `yield` の直後でモデルをアンロードします。このコードは、アプリケーションがリクエスト処理を「終了」した後、シャットダウン直前に実行されます。たとえばメモリや GPU のようなリソースを解放できます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`shutdown` は、アプリケーションを「停止」するときに発生します。
|
||||
|
||||
新しいバージョンを開始する必要があるか、単に実行をやめたくなったのかもしれません。🤷
|
||||
|
||||
///
|
||||
|
||||
### Lifespan 関数 { #lifespan-function }
|
||||
|
||||
まず注目すべきは、`yield` を使う非同期関数を定義していることです。これは「yield を使う依存関係(Dependencies)」にとてもよく似ています。
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
|
||||
|
||||
`yield` の前の前半は、アプリケーションが開始される「前」に実行されます。
|
||||
|
||||
`yield` の後半は、アプリケーションの処理が「終了」した「後」に実行されます。
|
||||
|
||||
### 非同期コンテキストマネージャ { #async-context-manager }
|
||||
|
||||
この関数には `@asynccontextmanager` がデコレートされています。
|
||||
|
||||
これにより、この関数は「非同期コンテキストマネージャ」になります。
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
|
||||
|
||||
Python の「コンテキストマネージャ」は、`with` 文で使えるものです。たとえば、`open()` はコンテキストマネージャとして使えます:
|
||||
|
||||
```Python
|
||||
with open("file.txt") as file:
|
||||
file.read()
|
||||
```
|
||||
|
||||
最近の Python には「非同期コンテキストマネージャ」もあります。`async with` で使います:
|
||||
|
||||
```Python
|
||||
async with lifespan(app):
|
||||
await do_stuff()
|
||||
```
|
||||
|
||||
このようにコンテキストマネージャ(または非同期コンテキストマネージャ)を作ると、`with` ブロックに入る前に `yield` より前のコードが実行され、`with` ブロックを出た後に `yield` より後ろのコードが実行されます。
|
||||
|
||||
上のコード例では直接それを使ってはいませんが、FastAPI に渡して内部で使ってもらいます。
|
||||
|
||||
`FastAPI` アプリの `lifespan` パラメータは「非同期コンテキストマネージャ」を受け取るので、新しく作った `lifespan` 非同期コンテキストマネージャを渡せます。
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
|
||||
|
||||
## 代替のイベント(非推奨) { #alternative-events-deprecated }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
推奨される方法は、上で説明したとおり `FastAPI` アプリの `lifespan` パラメータを使って「起動」と「シャットダウン」を扱うことです。`lifespan` パラメータを指定すると、`startup` と `shutdown` のイベントハンドラは呼び出されなくなります。`lifespan` かイベントか、どちらか一方であり、両方同時ではありません。
|
||||
|
||||
この節は読み飛ばしてもかまいません。
|
||||
|
||||
///
|
||||
|
||||
起動時とシャットダウン時に実行されるロジックを定義する別の方法もあります。
|
||||
|
||||
アプリケーションが起動する前、またはシャットダウンするときに実行する必要があるイベントハンドラ(関数)を定義できます。
|
||||
|
||||
これらの関数は `async def` でも、通常の `def` でも構いません。
|
||||
|
||||
### `startup` イベント { #startup-event }
|
||||
|
||||
アプリケーションが開始される前に実行すべき関数を追加するには、イベント `"startup"` で宣言します:
|
||||
|
||||
{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
|
||||
|
||||
この場合、`startup` のイベントハンドラ関数は items の「データベース」(単なる `dict`)をいくつかの値で初期化します。
|
||||
|
||||
イベントハンドラ関数は複数追加できます。
|
||||
|
||||
すべての `startup` イベントハンドラが完了するまで、アプリケーションはリクエストの受け付けを開始しません。
|
||||
|
||||
### `shutdown` イベント { #shutdown-event }
|
||||
|
||||
アプリケーションがシャットダウンするときに実行すべき関数を追加するには、イベント `"shutdown"` で宣言します:
|
||||
|
||||
{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
|
||||
|
||||
ここでは、`shutdown` のイベントハンドラ関数が、テキスト行 `"Application shutdown"` をファイル `log.txt` に書き込みます。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`open()` 関数の `mode="a"` は「追加」(append)を意味します。つまり、そのファイルに既にある内容を上書きせず、行が後ろに追記されます。
|
||||
|
||||
///
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
この例では、ファイルを扱う標準の Python 関数 `open()` を使っています。
|
||||
|
||||
そのため、ディスクへの書き込みを「待つ」必要がある I/O(入力/出力)が関わります。
|
||||
|
||||
しかし `open()` 自体は `async` や `await` を使いません。
|
||||
|
||||
したがって、イベントハンドラ関数は `async def` ではなく通常の `def` で宣言しています。
|
||||
|
||||
///
|
||||
|
||||
### `startup` と `shutdown` をまとめて { #startup-and-shutdown-together }
|
||||
|
||||
起動時とシャットダウン時のロジックは関連していることが多いです。何かを開始してから終了したい、リソースを獲得してから解放したい、などです.
|
||||
|
||||
共有するロジックや変数のない別々の関数でそれを行うのは難しく、グローバル変数などに値を保存する必要が出てきます。
|
||||
|
||||
そのため、現在は上で説明したとおり `lifespan` を使うことが推奨されています。
|
||||
|
||||
## 技術詳細 { #technical-details }
|
||||
|
||||
技術が気になる方への細かな詳細です。🤓
|
||||
|
||||
内部的には、ASGI の技術仕様において、これは <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan プロトコル</a> の一部であり、`startup` と `shutdown` というイベントが定義されています。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
Starlette の `lifespan` ハンドラについては、<a href="https://www.starlette.dev/lifespan/" class="external-link" target="_blank">Starlette の Lifespan ドキュメント</a>で詳しく読むことができます。
|
||||
|
||||
コードの他の領域で使える lifespan の状態をどのように扱うかも含まれています。
|
||||
|
||||
///
|
||||
|
||||
## サブアプリケーション { #sub-applications }
|
||||
|
||||
🚨 これらの lifespan イベント(startup と shutdown)はメインのアプリケーションに対してのみ実行され、[サブアプリケーション - マウント](sub-applications.md){.internal-link target=_blank} には実行されないことに注意してください。
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user