Sync fastapi docs from 11614be9 on 2026-03-11
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -109,7 +109,7 @@ En endpoints de WebSocket puedes importar desde `fastapi` y usar:
|
||||
|
||||
Funcionan de la misma manera que para otros endpoints de FastAPI/*path operations*:
|
||||
|
||||
{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *}
|
||||
{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}
|
||||
|
||||
/// info | Información
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -2,17 +2,33 @@
|
||||
|
||||
Puedes montar aplicaciones WSGI como viste con [Sub Aplicaciones - Mounts](sub-applications.md){.internal-link target=_blank}, [Detrás de un Proxy](behind-a-proxy.md){.internal-link target=_blank}.
|
||||
|
||||
Para eso, puedes usar `WSGIMiddleware` y usarlo para envolver tu aplicación WSGI, por ejemplo, Flask, Django, etc.
|
||||
Para eso, puedes usar el `WSGIMiddleware` y usarlo para envolver tu aplicación WSGI, por ejemplo, Flask, Django, etc.
|
||||
|
||||
## Usando `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
Necesitas importar `WSGIMiddleware`.
|
||||
/// info | Información
|
||||
|
||||
Esto requiere instalar `a2wsgi`, por ejemplo con `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
Necesitas importar `WSGIMiddleware` de `a2wsgi`.
|
||||
|
||||
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[2:3,3] *}
|
||||
{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Anteriormente, se recomendaba usar `WSGIMiddleware` de `fastapi.middleware.wsgi`, pero ahora está deprecado.
|
||||
|
||||
Se aconseja usar el paquete `a2wsgi` en su lugar. El uso sigue siendo el mismo.
|
||||
|
||||
Solo asegúrate de tener instalado el paquete `a2wsgi` e importar `WSGIMiddleware` correctamente desde `a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
## Revisa { #check-it }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user