@ -11,7 +11,7 @@ Las pruebas añadidas aquí serán vistas por todas las personas que diseñan pr
* Revisa si las cosas están bien en la traducción.
* Revisa si las cosas están bien en la traducción.
* Si es necesario, mejora tu prompt específico del idioma, el prompt general, o el documento en inglés.
* Si es necesario, mejora tu prompt específico del idioma, el prompt general, o el documento en inglés.
* Luego corrige manualmente los problemas restantes en la traducción para que sea una buena traducción.
* Luego corrige manualmente los problemas restantes en la traducción para que sea una buena traducción.
* Vuelve a traducir, teniendo la buena traducción en su lugar. El resultado ideal sería que el LLM ya no hiciera cambios a la traducción. Eso significa que el prompt general y tu prompt específico del idioma están tan bien como pueden estar (A veces hará algunos cambios aparentemente aleatorios; la razón es que <ahref="https://doublespeak.chat/#/handbook#deterministic-output"class="external-link"target="_blank">los LLMs no son algoritmos deterministas</a>).
* Vuelve a traducir, teniendo la buena traducción en su lugar. El resultado ideal sería que el LLM ya no hiciera cambios a la traducción. Eso significa que el prompt general y tu prompt específico del idioma están tan bien como pueden estar (A veces hará algunos cambios aparentemente aleatorios; la razón es que [los LLMs no son algoritmos deterministas](https://doublespeak.chat/#/handbook#deterministic-output)).
Las pruebas:
Las pruebas:
@ -169,15 +169,15 @@ Consulta las secciones `### Special blocks` y `### Tab blocks` en el prompt gene
El texto del enlace debe traducirse, la dirección del enlace debe permanecer sin cambios:
El texto del enlace debe traducirse, la dirección del enlace debe permanecer sin cambios:
* [Enlace al encabezado de arriba](#code-snippets)
* [Enlace al encabezado de arriba](#code-snippets)
@ -16,11 +16,11 @@ Incluso si tu aplicación de **FastAPI** usa funciones `def` normales en lugar d
El `TestClient` hace algo de magia interna para llamar a la aplicación FastAPI asíncrona en tus funciones de test `def` normales, usando pytest estándar. Pero esa magia ya no funciona cuando lo usamos dentro de funciones asíncronas. Al ejecutar nuestros tests de manera asíncrona, ya no podemos usar el `TestClient` dentro de nuestras funciones de test.
El `TestClient` hace algo de magia interna para llamar a la aplicación FastAPI asíncrona en tus funciones de test `def` normales, usando pytest estándar. Pero esa magia ya no funciona cuando lo usamos dentro de funciones asíncronas. Al ejecutar nuestros tests de manera asíncrona, ya no podemos usar el `TestClient` dentro de nuestras funciones de test.
El `TestClient` está basado en <ahref="https://www.python-httpx.org"class="external-link"target="_blank">HTTPX</a>, y afortunadamente, podemos usarlo directamente para probar la API.
El `TestClient` está basado en [HTTPX](https://www.python-httpx.org), y afortunadamente, podemos usarlo directamente para probar la API.
## Ejemplo { #example }
## Ejemplo { #example }
Para un ejemplo simple, consideremos una estructura de archivos similar a la descrita en [Aplicaciones Más Grandes](../tutorial/bigger-applications.md){.internal-link target=_blank} y [Testing](../tutorial/testing.md){.internal-link target=_blank}:
Para un ejemplo simple, consideremos una estructura de archivos similar a la descrita en [Aplicaciones Más Grandes](../tutorial/bigger-applications.md) y [Testing](../tutorial/testing.md):
```
```
.
.
@ -84,7 +84,7 @@ Nota que estamos usando async/await con el nuevo `AsyncClient`: el request es as
/// warning | Advertencia
/// warning | Advertencia
Si tu aplicación depende de eventos de lifespan, el `AsyncClient` no activará estos eventos. Para asegurarte de que se activen, usa `LifespanManager` de <ahref="https://github.com/florimondmanca/asgi-lifespan#usage"class="external-link"target="_blank">florimondmanca/asgi-lifespan</a>.
Si tu aplicación depende de eventos de lifespan, el `AsyncClient` no activará estos eventos. Para asegurarte de que se activen, usa `LifespanManager` de [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage).
///
///
@ -94,6 +94,6 @@ Al ser la función de test asíncrona, ahora también puedes llamar (y `await`)
/// tip | Consejo
/// tip | Consejo
Si encuentras un `RuntimeError: Task attached to a different loop` al integrar llamadas a funciones asíncronas en tus tests (por ejemplo, cuando usas <ahref="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop"class="external-link"target="_blank">MotorClient de MongoDB</a>), recuerda crear instances de objetos que necesiten un loop de eventos solo dentro de funciones async, por ejemplo, en un callback `@app.on_event("startup")`.
Si encuentras un `RuntimeError: Task attached to a different loop` al integrar llamadas a funciones asíncronas en tus tests (por ejemplo, cuando usas [MotorClient de MongoDB](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)), recuerda crear instances de objetos que necesiten un loop de eventos solo dentro de funciones async, por ejemplo, en un callback `@app.on_event("startup")`.
@ -150,11 +150,11 @@ Debido a eso, ahora se recomienda en su lugar usar el `lifespan` como se explic
Solo un detalle técnico para los nerds curiosos. 🤓
Solo un detalle técnico para los nerds curiosos. 🤓
Por debajo, en la especificación técnica ASGI, esto es parte del <ahref="https://asgi.readthedocs.io/en/latest/specs/lifespan.html"class="external-link"target="_blank">Protocolo de Lifespan</a>, y define eventos llamados `startup` y `shutdown`.
Por debajo, en la especificación técnica ASGI, esto es parte del [Protocolo de Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), y define eventos llamados `startup` y `shutdown`.
/// info | Información
/// info | Información
Puedes leer más sobre los manejadores `lifespan` de Starlette en <ahref="https://www.starlette.dev/lifespan/"class="external-link"target="_blank">la documentación de `Lifespan` de Starlette</a>.
Puedes leer más sobre los manejadores `lifespan` de Starlette en [la documentación de `Lifespan` de Starlette](https://www.starlette.dev/lifespan/).
Incluyendo cómo manejar el estado de lifespan que puede ser usado en otras áreas de tu código.
Incluyendo cómo manejar el estado de lifespan que puede ser usado en otras áreas de tu código.
@ -162,4 +162,4 @@ Incluyendo cómo manejar el estado de lifespan que puede ser usado en otras áre
## Sub Aplicaciones { #sub-applications }
## Sub Aplicaciones { #sub-applications }
🚨 Ten en cuenta que estos eventos de lifespan (startup y shutdown) solo serán ejecutados para la aplicación principal, no para [Sub Aplicaciones - Mounts](sub-applications.md){.internal-link target=_blank}.
🚨 Ten en cuenta que estos eventos de lifespan (startup y shutdown) solo serán ejecutados para la aplicación principal, no para [Sub Aplicaciones - Mounts](sub-applications.md).
En el tutorial principal leíste cómo agregar [Middleware Personalizado](../tutorial/middleware.md){.internal-link target=_blank} a tu aplicación.
En el tutorial principal leíste cómo agregar [Middleware Personalizado](../tutorial/middleware.md) a tu aplicación.
Y luego también leíste cómo manejar [CORS con el `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}.
Y luego también leíste cómo manejar [CORS con el `CORSMiddleware`](../tutorial/cors.md).
En esta sección veremos cómo usar otros middlewares.
En esta sección veremos cómo usar otros middlewares.
@ -91,7 +91,7 @@ Hay muchos otros middlewares ASGI.
Por ejemplo:
Por ejemplo:
* <ahref="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py"class="external-link"target="_blank">`ProxyHeadersMiddleware` de Uvicorn</a>
* [`ProxyHeadersMiddleware` de Uvicorn](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)
Para ver otros middlewares disponibles, revisa <ahref="https://www.starlette.dev/middleware/"class="external-link"target="_blank">la documentación de Middleware de Starlette</a> y la <ahref="https://github.com/florimondmanca/awesome-asgi"class="external-link"target="_blank">Lista ASGI Awesome</a>.
Para ver otros middlewares disponibles, revisa [la documentación de Middleware de Starlette](https://www.starlette.dev/middleware/) y la [Lista ASGI Awesome](https://github.com/florimondmanca/awesome-asgi).
@ -60,7 +60,7 @@ Eso define los metadatos sobre el response principal de una *path operation*.
También puedes declarar responses adicionales con sus modelos, códigos de estado, etc.
También puedes declarar responses adicionales con sus modelos, códigos de estado, etc.
Hay un capítulo entero en la documentación sobre ello, puedes leerlo en [Responses Adicionales en OpenAPI](additional-responses.md){.internal-link target=_blank}.
Hay un capítulo entero en la documentación sobre ello, puedes leerlo en [Responses Adicionales en OpenAPI](additional-responses.md).
## OpenAPI Extra { #openapi-extra }
## OpenAPI Extra { #openapi-extra }
@ -68,7 +68,7 @@ Cuando declaras una *path operation* en tu aplicación, **FastAPI** genera autom
/// note | Detalles técnicos
/// note | Detalles técnicos
En la especificación de OpenAPI se llama el <ahref="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object"class="external-link"target="_blank">Objeto de Operación</a>.
En la especificación de OpenAPI se llama el [Objeto de Operación](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object).
///
///
@ -82,7 +82,7 @@ Este esquema de OpenAPI específico de *path operation* normalmente se genera au
Este es un punto de extensión de bajo nivel.
Este es un punto de extensión de bajo nivel.
Si solo necesitas declarar responses adicionales, una forma más conveniente de hacerlo es con [Responses Adicionales en OpenAPI](additional-responses.md){.internal-link target=_blank}.
Si solo necesitas declarar responses adicionales, una forma más conveniente de hacerlo es con [Responses Adicionales en OpenAPI](additional-responses.md).
///
///
@ -141,7 +141,7 @@ Podrías hacer eso con `openapi_extra`:
En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el request body ni siquiera es <dfntitle="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.
En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el request body ni siquiera es <dfntitle="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 hacer parse de él de alguna manera.
Sin embargo, podemos declarar el esquema esperado para el request body.
Sin embargo, podemos declarar el esquema esperado para el request body.
@ -157,9 +157,9 @@ Por ejemplo, en esta aplicación no usamos la funcionalidad integrada de FastAPI
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.
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.
Luego usamos el request directamente, y extraemos el cuerpo como `bytes`. Esto significa que FastAPI ni siquiera intentará parsear la carga útil del request como JSON.
Luego usamos el request directamente, y extraemos el cuerpo como `bytes`. Esto significa que FastAPI ni siquiera intentará hacer parse de la carga útil del request como JSON.
Y luego en nuestro código, parseamos ese contenido YAML directamente, y nuevamente estamos usando el mismo modelo Pydantic para validar el contenido YAML:
Y luego en nuestro código, hacemos parse de ese contenido YAML directamente, y nuevamente estamos usando el mismo modelo Pydantic para validar el contenido YAML:
@ -8,7 +8,7 @@ Por esta razón, es común proporcionarlas en variables de entorno que son leíd
/// tip | Consejo
/// tip | Consejo
Para entender las variables de entorno, puedes leer [Variables de Entorno](../environment-variables.md){.internal-link target=_blank}.
Para entender las variables de entorno, puedes leer [Variables de Entorno](../environment-variables.md).
///
///
@ -20,11 +20,11 @@ Eso significa que cualquier valor leído en Python desde una variable de entorno
## Pydantic `Settings` { #pydantic-settings }
## Pydantic `Settings` { #pydantic-settings }
Afortunadamente, Pydantic proporciona una gran utilidad para manejar estas configuraciones provenientes de variables de entorno con <ahref="https://docs.pydantic.dev/latest/concepts/pydantic_settings/"class="external-link"target="_blank">Pydantic: Settings management</a>.
Afortunadamente, Pydantic proporciona una gran utilidad para manejar estas configuraciones provenientes de variables de entorno con [Pydantic: Settings management](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).
Primero, asegúrate de crear tu [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, actívalo y luego instala el paquete `pydantic-settings`:
Primero, asegúrate de crear tu [entorno virtual](../virtual-environments.md), actívalo y luego instala el paquete `pydantic-settings`:
<divclass="termy">
<divclass="termy">
@ -100,7 +100,7 @@ Y el `items_per_user` mantendría su valor por defecto de `50`.
## Configuraciones en otro módulo { #settings-in-another-module }
## Configuraciones en otro módulo { #settings-in-another-module }
Podrías poner esas configuraciones en otro archivo de módulo como viste en [Aplicaciones Más Grandes - Múltiples Archivos](../tutorial/bigger-applications.md){.internal-link target=_blank}.
Podrías poner esas configuraciones en otro archivo de módulo como viste en [Aplicaciones Más Grandes - Múltiples Archivos](../tutorial/bigger-applications.md).
Por ejemplo, podrías tener un archivo `config.py` con:
Por ejemplo, podrías tener un archivo `config.py` con:
@ -112,7 +112,7 @@ Y luego usarlo en un archivo `main.py`:
/// tip | Consejo
/// tip | Consejo
También necesitarías un archivo `__init__.py` como viste en [Aplicaciones Más Grandes - Múltiples Archivos](../tutorial/bigger-applications.md){.internal-link target=_blank}.
También necesitarías un archivo `__init__.py` como viste en [Aplicaciones Más Grandes - Múltiples Archivos](../tutorial/bigger-applications.md).
///
///
@ -172,7 +172,7 @@ Pero un archivo dotenv realmente no tiene que tener ese nombre exacto.
///
///
Pydantic tiene soporte para leer desde estos tipos de archivos usando un paquete externo. Puedes leer más en <ahref="https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support"class="external-link"target="_blank">Pydantic Settings: Dotenv (.env) support</a>.
Pydantic tiene soporte para leer desde estos tipos de archivos usando un paquete externo. Puedes leer más en [Pydantic Settings: Dotenv (.env) support](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support).
/// tip | Consejo
/// tip | Consejo
@ -197,7 +197,7 @@ Y luego actualizar tu `config.py` con:
/// tip | Consejo
/// tip | Consejo
El atributo `model_config` se usa solo para configuración de Pydantic. Puedes leer más en <ahref="https://docs.pydantic.dev/latest/concepts/config/"class="external-link"target="_blank">Pydantic: Concepts: Configuration</a>.
El atributo `model_config` se usa solo para configuración de Pydantic. Puedes leer más en [Pydantic: Concepts: Configuration](https://docs.pydantic.dev/latest/concepts/config/).
///
///
@ -291,7 +291,7 @@ En el caso de nuestra dependencia `get_settings()`, la función ni siquiera toma
De esa manera, se comporta casi como si fuera solo una variable global. Pero como usa una función de dependencia, entonces podemos sobrescribirla fácilmente para las pruebas.
De esa manera, se comporta casi como si fuera solo una variable global. Pero como usa una función de dependencia, entonces podemos sobrescribirla fácilmente para las pruebas.
`@lru_cache` es parte de `functools`, que es parte del paquete estándar de Python, puedes leer más sobre él en las <ahref="https://docs.python.org/3/library/functools.html#functools.lru_cache"class="external-link"target="_blank">docs de Python para `@lru_cache`</a>.
`@lru_cache` es parte de `functools`, que es parte del paquete estándar de Python, puedes leer más sobre él en las [docs de Python para `@lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache).
@ -8,7 +8,7 @@ Hay utilidades para configurarlo fácilmente que puedes usar directamente en tu
## Instala dependencias { #install-dependencies }
## Instala dependencias { #install-dependencies }
Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo e instalar `jinja2`:
Asegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo e instalar `jinja2`:
<divclass="termy">
<divclass="termy">
@ -123,4 +123,4 @@ Y porque estás usando `StaticFiles`, ese archivo CSS sería servido automática
## Más detalles { #more-details }
## Más detalles { #more-details }
Para más detalles, incluyendo cómo testear plantillas, revisa <ahref="https://www.starlette.dev/templates/"class="external-link"target="_blank">la documentación de Starlette sobre plantillas</a>.
Para más detalles, incluyendo cómo testear plantillas, revisa [la documentación de Starlette sobre plantillas](https://www.starlette.dev/templates/).
@ -8,6 +8,6 @@ Para esto, usas el `TestClient` en un statement `with`, conectándote al WebSock
/// note | Nota
/// note | Nota
Para más detalles, revisa la documentación de Starlette sobre <ahref="https://www.starlette.dev/testclient/#testing-websocket-sessions"class="external-link"target="_blank">probar WebSockets</a>.
Para más detalles, revisa la documentación de Starlette sobre [probar WebSockets](https://www.starlette.dev/testclient/#testing-websocket-sessions).
Puedes usar <ahref="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API"class="external-link"target="_blank">WebSockets</a> con **FastAPI**.
Puedes usar [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) con **FastAPI**.
## Instalar `websockets` { #install-websockets }
## Instalar `websockets` { #install-websockets }
Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo e instalar `websockets` (un paquete de Python que facilita usar el protocolo "WebSocket"):
Asegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo e instalar `websockets` (un paquete de Python que facilita usar el protocolo "WebSocket"):
<divclass="termy">
<divclass="termy">
@ -64,19 +64,19 @@ Puedes recibir y enviar datos binarios, de texto y JSON.
## Pruébalo { #try-it }
## Pruébalo { #try-it }
Si tu archivo se llama `main.py`, ejecuta tu aplicación con:
Pon tu código en un archivo `main.py` y luego ejecuta tu aplicación:
<divclass="termy">
<divclass="termy">
```console
```console
$ fastapi dev main.py
$ fastapi dev
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
```
</div>
</div>
Abre tu navegador en <ahref="http://127.0.0.1:8000"class="external-link"target="_blank">http://127.0.0.1:8000</a>.
Abre tu navegador en [http://127.0.0.1:8000](http://127.0.0.1:8000).
Verás una página simple como:
Verás una página simple como:
@ -115,25 +115,25 @@ Funcionan de la misma manera que para otros endpoints de FastAPI/*path operation
Como esto es un WebSocket no tiene mucho sentido lanzar un `HTTPException`, en su lugar lanzamos un `WebSocketException`.
Como esto es un WebSocket no tiene mucho sentido lanzar un `HTTPException`, en su lugar lanzamos un `WebSocketException`.
Puedes usar un código de cierre de los <ahref="https://tools.ietf.org/html/rfc6455#section-7.4.1"class="external-link"target="_blank">códigos válidos definidos en la especificación</a>.
Puedes usar un código de cierre de los [códigos válidos definidos en la especificación](https://tools.ietf.org/html/rfc6455#section-7.4.1).
///
///
### Prueba los WebSockets con dependencias { #try-the-websockets-with-dependencies }
### Prueba los WebSockets con dependencias { #try-the-websockets-with-dependencies }
Si tu archivo se llama `main.py`, ejecuta tu aplicación con:
Ejecuta tu aplicación:
<divclass="termy">
<divclass="termy">
```console
```console
$ fastapi dev main.py
$ fastapi dev
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
```
</div>
</div>
Abre tu navegador en <ahref="http://127.0.0.1:8000"class="external-link"target="_blank">http://127.0.0.1:8000</a>.
Abre tu navegador en [http://127.0.0.1:8000](http://127.0.0.1:8000).
Ahí puedes establecer:
Ahí puedes establecer:
@ -174,7 +174,7 @@ La aplicación anterior es un ejemplo mínimo y simple para demostrar cómo mane
Pero ten en cuenta que, como todo se maneja en memoria, en una sola lista, solo funcionará mientras el proceso esté en ejecución, y solo funcionará con un solo proceso.
Pero ten en cuenta que, como todo se maneja en memoria, en una sola lista, solo funcionará mientras el proceso esté en ejecución, y solo funcionará con un solo proceso.
Si necesitas algo fácil de integrar con FastAPI pero que sea más robusto, soportado por Redis, PostgreSQL u otros, revisa <ahref="https://github.com/encode/broadcaster"class="external-link"target="_blank">encode/broadcaster</a>.
Si necesitas algo fácil de integrar con FastAPI pero que sea más robusto, soportado por Redis, PostgreSQL u otros, revisa [encode/broadcaster](https://github.com/encode/broadcaster).
///
///
@ -182,5 +182,5 @@ Si necesitas algo fácil de integrar con FastAPI pero que sea más robusto, sopo
Para aprender más sobre las opciones, revisa la documentación de Starlette para:
Para aprender más sobre las opciones, revisa la documentación de Starlette para:
# Incluyendo WSGI - Flask, Django, otros { #including-wsgi-flask-django-others }
# Incluyendo WSGI - Flask, Django, otros { #including-wsgi-flask-django-others }
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}.
Puedes montar aplicaciones WSGI como viste con [Sub Aplicaciones - Mounts](sub-applications.md), [Detrás de un Proxy](behind-a-proxy.md).
Para eso, puedes usar el `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.
@ -36,13 +36,13 @@ Ahora, cada request bajo el path `/v1/` será manejado por la aplicación Flask.
Y el resto será manejado por **FastAPI**.
Y el resto será manejado por **FastAPI**.
Si lo ejecutas y vas a <ahref="http://localhost:8000/v1/"class="external-link"target="_blank">http://localhost:8000/v1/</a> verás el response de Flask:
Si lo ejecutas y vas a [http://localhost:8000/v1/](http://localhost:8000/v1/) verás el response de Flask:
```txt
```txt
Hello, World from Flask!
Hello, World from Flask!
```
```
Y si vas a <ahref="http://localhost:8000/v2"class="external-link"target="_blank">http://localhost:8000/v2</a> verás el response de FastAPI:
Y si vas a [http://localhost:8000/v2](http://localhost:8000/v2) verás el response de FastAPI:
@ -65,7 +65,7 @@ print(f"Hello {name} from Python")
/// tip | Consejo
/// tip | Consejo
El segundo argumento de <ahref="https://docs.python.org/3.8/library/os.html#os.getenv"class="external-link"target="_blank">`os.getenv()`</a> es el valor por defecto a retornar.
El segundo argumento de [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) es el valor por defecto a retornar.
Si no se proporciona, es `None` por defecto; aquí proporcionamos `"World"` como el valor por defecto para usar.
Si no se proporciona, es `None` por defecto; aquí proporcionamos `"World"` como el valor por defecto para usar.
@ -153,7 +153,7 @@ Hello World from Python
/// tip | Consejo
/// tip | Consejo
Puedes leer más al respecto en <ahref="https://12factor.net/config"class="external-link"target="_blank">The Twelve-Factor App: Config</a>.
Puedes leer más al respecto en [The Twelve-Factor App: Config](https://12factor.net/config).
///
///
@ -163,7 +163,7 @@ Estas variables de entorno solo pueden manejar **strings de texto**, ya que son
Esto significa que **cualquier valor** leído en Python desde una variable de entorno **será un `str`**, y cualquier conversión a un tipo diferente o cualquier validación tiene que hacerse en el código.
Esto significa que **cualquier valor** leído en Python desde una variable de entorno **será un `str`**, y cualquier conversión a un tipo diferente o cualquier validación tiene que hacerse en el código.
Aprenderás más sobre cómo usar variables de entorno para manejar **configuraciones de aplicación** en la [Guía del Usuario Avanzado - Ajustes y Variables de Entorno](./advanced/settings.md){.internal-link target=_blank}.
Aprenderás más sobre cómo usar variables de entorno para manejar **configuraciones de aplicación** en la [Guía del Usuario Avanzado - Ajustes y Variables de Entorno](./advanced/settings.md).
## Variable de Entorno `PATH` { #path-environment-variable }
## Variable de Entorno `PATH` { #path-environment-variable }
Esta información será útil al aprender sobre [Entornos Virtuales](virtual-environments.md){.internal-link target=_blank}.
Esta información será útil al aprender sobre [Entornos Virtuales](virtual-environments.md).
## Conclusión { #conclusion }
## Conclusión { #conclusion }
Con esto deberías tener una comprensión básica de qué son las **variables de entorno** y cómo usarlas en Python.
Con esto deberías tener una comprensión básica de qué son las **variables de entorno** y cómo usarlas en Python.
También puedes leer más sobre ellas en la <ahref="https://en.wikipedia.org/wiki/Environment_variable"class="external-link"target="_blank">Wikipedia para Variable de Entorno</a>.
También puedes leer más sobre ellas en la [Wikipedia para Variable de Entorno](https://en.wikipedia.org/wiki/Environment_variable).
En muchos casos no es muy obvio cómo las variables de entorno serían útiles y aplicables de inmediato. Pero siguen apareciendo en muchos escenarios diferentes cuando estás desarrollando, así que es bueno conocerlas.
En muchos casos no es muy obvio cómo las variables de entorno serían útiles y aplicables de inmediato. Pero siguen apareciendo en muchos escenarios diferentes cuando estás desarrollando, así que es bueno conocerlas.
Eso no es lo mismo que declarar valores predeterminados como sería con:
Eso no es lo mismo que declarar valores por defecto como sería con:
```Python
```Python
first_name="john", last_name="doe"
first_name="john", last_name="doe"
@ -269,7 +269,7 @@ No significa "`one_person` es la **clase** llamada `Person`".
## Modelos Pydantic { #pydantic-models }
## Modelos Pydantic { #pydantic-models }
<ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic</a> es un paquete de Python para realizar la validación de datos.
[Pydantic](https://docs.pydantic.dev/) es un paquete de Python para realizar la validación de datos.
Declaras la "forma" de los datos como clases con atributos.
Declaras la "forma" de los datos como clases con atributos.
@ -285,13 +285,13 @@ Un ejemplo de la documentación oficial de Pydantic:
/// info | Información
/// info | Información
Para saber más sobre <ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic, revisa su documentación</a>.
Para saber más sobre [Pydantic, revisa su documentación](https://docs.pydantic.dev/).
///
///
**FastAPI** está completamente basado en Pydantic.
**FastAPI** está completamente basado en Pydantic.
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}.
Verás mucho más de todo esto en práctica en el [Tutorial - Guía del Usuario](tutorial/index.md).
## Anotaciones de tipos con metadata { #type-hints-with-metadata-annotations }
## Anotaciones de tipos con metadata { #type-hints-with-metadata-annotations }
@ -337,12 +337,12 @@ Con **FastAPI** declaras parámetros con anotaciones de tipos y obtienes:
* **Documentar** la API usando OpenAPI:
* **Documentar** la API usando OpenAPI:
* Que luego es usada por las interfaces de documentación interactiva automática.
* Que luego es usada por las interfaces de documentación interactiva automática.
Todo esto puede sonar abstracto. No te preocupes. Verás todo esto en acción en el [Tutorial - Guía del Usuario](tutorial/index.md){.internal-link target=_blank}.
Todo esto puede sonar abstracto. No te preocupes. Verás todo esto en acción en el [Tutorial - Guía del Usuario](tutorial/index.md).
Lo importante es que al usar tipos estándar de Python, en un solo lugar (en lugar de agregar más clases, decoradores, etc.), **FastAPI** hará gran parte del trabajo por ti.
Lo importante es que al usar tipos estándar de Python, en un solo lugar (en lugar de agregar más clases, decoradores, etc.), **FastAPI** hará gran parte del trabajo por ti.
/// info | Información
/// info | Información
Si ya revisaste todo el tutorial y volviste para ver más sobre tipos, un buen recurso es <ahref="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html"class="external-link"target="_blank">la "cheat sheet" de `mypy`</a>.
Si ya revisaste todo el tutorial y volviste para ver más sobre tipos, un buen recurso es [la "cheat sheet" de `mypy`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html).
@ -61,7 +61,7 @@ Y luego otra tarea en segundo plano generada en la *path operation function* esc
## Detalles Técnicos { #technical-details }
## Detalles Técnicos { #technical-details }
La clase `BackgroundTasks` proviene directamente de <ahref="https://www.starlette.dev/background/"class="external-link"target="_blank">`starlette.background`</a>.
La clase `BackgroundTasks` proviene directamente de [`starlette.background`](https://www.starlette.dev/background/).
Se importa/incluye directamente en FastAPI para que puedas importarla desde `fastapi` y evitar importar accidentalmente la alternativa `BackgroundTask` (sin la `s` al final) de `starlette.background`.
Se importa/incluye directamente en FastAPI para que puedas importarla desde `fastapi` y evitar importar accidentalmente la alternativa `BackgroundTask` (sin la `s` al final) de `starlette.background`.
@ -69,11 +69,11 @@ Al usar solo `BackgroundTasks` (y no `BackgroundTask`), es posible usarla como u
Todavía es posible usar `BackgroundTask` solo en FastAPI, pero debes crear el objeto en tu código y devolver una `Response` de Starlette incluyéndolo.
Todavía es posible usar `BackgroundTask` solo en FastAPI, pero debes crear el objeto en tu código y devolver una `Response` de Starlette incluyéndolo.
Puedes ver más detalles en <ahref="https://www.starlette.dev/background/"class="external-link"target="_blank">la documentación oficial de Starlette sobre Background Tasks</a>.
Puedes ver más detalles en [la documentación oficial de Starlette sobre Background Tasks](https://www.starlette.dev/background/).
## Advertencia { #caveat }
## Advertencia { #caveat }
Si necesitas realizar una computación intensa en segundo plano y no necesariamente necesitas que se ejecute por el mismo proceso (por ejemplo, no necesitas compartir memoria, variables, etc.), podrías beneficiarte del uso de otras herramientas más grandes como <ahref="https://docs.celeryq.dev"class="external-link"target="_blank">Celery</a>.
Si necesitas realizar una computación intensa en segundo plano y no necesariamente necesitas que se ejecute por el mismo proceso (por ejemplo, no necesitas compartir memoria, variables, etc.), podrías beneficiarte del uso de otras herramientas más grandes como [Celery](https://docs.celeryq.dev).
Tienden a requerir configuraciones más complejas, un gestor de cola de mensajes/trabajos, como RabbitMQ o Redis, pero te permiten ejecutar tareas en segundo plano en múltiples procesos, y especialmente, en múltiples servidores.
Tienden a requerir configuraciones más complejas, un gestor de cola de mensajes/trabajos, como RabbitMQ o Redis, pero te permiten ejecutar tareas en segundo plano en múltiples procesos, y especialmente, en múltiples servidores.
@ -123,7 +123,7 @@ Ahora utilizaremos una dependencia simple para leer un header `X-Token` personal
Estamos usando un header inventado para simplificar este ejemplo.
Estamos usando un header inventado para simplificar este ejemplo.
Pero en casos reales obtendrás mejores resultados usando las [utilidades de Seguridad](security/index.md){.internal-link target=_blank} integradas.
Pero en casos reales obtendrás mejores resultados usando las [utilidades de Seguridad](security/index.md) integradas.
///
///
@ -169,7 +169,7 @@ Y podemos agregar una lista de `dependencies` que se añadirá a todas las *path
/// tip | Consejo
/// tip | Consejo
Nota que, al igual que [dependencias en decoradores de *path operations*](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, ningún valor será pasado a tu *path operation function*.
Nota que, al igual que [dependencias en decoradores de *path operations*](dependencies/dependencies-in-path-operation-decorators.md), ningún valor será pasado a tu *path operation function*.
///
///
@ -185,8 +185,8 @@ El resultado final es que los paths de item son ahora:
* Todos incluirán las `responses` predefinidas.
* Todos incluirán las `responses` predefinidas.
* Todas estas *path operations* tendrán la lista de `dependencies` evaluadas/ejecutadas antes de ellas.
* Todas estas *path operations* tendrán la lista de `dependencies` evaluadas/ejecutadas antes de ellas.
* Si también declaras dependencias en una *path operation* específica, **también se ejecutarán**.
* Si también declaras dependencias en una *path operation* específica, **también se ejecutarán**.
* Las dependencias del router se ejecutan primero, luego las [`dependencies` en el decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, y luego las dependencias de parámetros normales.
* Las dependencias del router se ejecutan primero, luego las [`dependencies` en el decorador](dependencies/dependencies-in-path-operation-decorators.md), y luego las dependencias de parámetros normales.
* También puedes agregar [dependencias de `Security` con `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
* También puedes agregar [dependencias de `Security` con `scopes`](../advanced/security/oauth2-scopes.md).
/// tip | Consejo
/// tip | Consejo
@ -303,7 +303,7 @@ Y como la mayor parte de tu lógica ahora vivirá en su propio módulo específi
Importas y creas una clase `FastAPI` como normalmente.
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`:
Y podemos incluso declarar [dependencias globales](dependencies/global-dependencies.md) que se combinarán con las dependencias para cada `APIRouter`:
@ -353,7 +353,7 @@ La segunda versión es un "import absoluto":
from app.routers import items, users
from app.routers import items, users
```
```
Para aprender más sobre Paquetes y Módulos de Python, lee <ahref="https://docs.python.org/3/tutorial/modules.html"class="external-link"target="_blank">la documentación oficial de Python sobre Módulos</a>.
Para aprender más sobre Paquetes y Módulos de Python, lee [la documentación oficial de Python sobre Módulos](https://docs.python.org/3/tutorial/modules.html).
///
///
@ -465,6 +465,37 @@ Como no podemos simplemente aislarlos y "montarlos" independientemente del resto
///
///
## Configurar el `entrypoint` en `pyproject.toml` { #configure-the-entrypoint-in-pyproject-toml }
Como tu objeto `app` de FastAPI vive en `app/main.py`, puedes configurar el `entrypoint` en tu archivo `pyproject.toml` así:
```toml
[tool.fastapi]
entrypoint = "app.main:app"
```
que es equivalente a importar como:
```python
from app.main import app
```
De esa manera el comando `fastapi` sabrá dónde encontrar tu app.
/// Note | Nota
También podrías pasar la ruta al comando, como:
```console
$ fastapi dev app/main.py
```
Pero tendrías que recordar pasar la ruta correcta cada vez que llames al comando `fastapi`.
Además, otras herramientas podrían no ser capaces de encontrarla, por ejemplo la [Extensión de VS Code](../editor-support.md) o [FastAPI Cloud](https://fastapicloud.com), así que se recomienda usar el `entrypoint` en `pyproject.toml`.
///
## Revisa la documentación automática de la API { #check-the-automatic-api-docs }
## Revisa la documentación automática de la API { #check-the-automatic-api-docs }
Ahora, ejecuta tu app:
Ahora, ejecuta tu app:
@ -472,14 +503,14 @@ Ahora, ejecuta tu app:
<divclass="termy">
<divclass="termy">
```console
```console
$ fastapi dev app/main.py
$ fastapi dev
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
```
</div>
</div>
Y abre la documentación en <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a>.
Y abre la documentación en [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
Verás la documentación automática de la API, incluyendo los paths de todos los submódulos, usando los paths correctos (y prefijos) y los tags correctos:
Verás la documentación automática de la API, incluyendo los paths de todos los submódulos, usando los paths correctos (y prefijos) y los tags correctos:
Con **FastAPI**, puedes definir, validar, documentar y usar modelos anidados de manera arbitraria (gracias a Pydantic).
Con **FastAPI**, puedes definir, validar, documentar y usar modelos profundamente anidados de manera arbitraria (gracias a Pydantic).
## Campos de lista { #list-fields }
## Campos de lista { #list-fields }
@ -96,7 +96,7 @@ Nuevamente, haciendo solo esa declaración, con **FastAPI** obtienes:
Además de tipos singulares normales como `str`, `int`, `float`, etc., puedes usar tipos singulares más complejos que heredan de `str`.
Además de tipos singulares normales como `str`, `int`, `float`, etc., puedes usar tipos singulares más complejos que heredan de `str`.
Para ver todas las opciones que tienes, revisa el <ahref="https://docs.pydantic.dev/latest/concepts/types/"class="external-link"target="_blank">Overview de Tipos de Pydantic</a>. Verás algunos ejemplos en el siguiente capítulo.
Para ver todas las opciones que tienes, Revisa [Resumen de tipos de Pydantic](https://docs.pydantic.dev/latest/concepts/types/). Verás algunos ejemplos en el siguiente capítulo.
Por ejemplo, como en el modelo `Image` tenemos un campo `url`, podemos declararlo como una instance de `HttpUrl` de Pydantic en lugar de un `str`:
Por ejemplo, como en el modelo `Image` tenemos un campo `url`, podemos declararlo como una instance de `HttpUrl` de Pydantic en lugar de un `str`:
## Actualización reemplazando con `PUT` { #update-replacing-with-put }
## Actualización reemplazando con `PUT` { #update-replacing-with-put }
Para actualizar un ítem puedes utilizar la operación de <ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT"class="external-link"target="_blank">HTTP `PUT`</a>.
Para actualizar un ítem puedes utilizar la operación de [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT).
Puedes usar el `jsonable_encoder` para convertir los datos de entrada en datos que se puedan almacenar como JSON (por ejemplo, con una base de datos NoSQL). Por ejemplo, convirtiendo `datetime` a `str`.
Puedes usar el `jsonable_encoder` para convertir los datos de entrada en datos que se puedan almacenar como JSON (por ejemplo, con una base de datos NoSQL). Por ejemplo, convirtiendo `datetime` a `str`.
@ -28,7 +28,7 @@ Y los datos se guardarían con ese "nuevo" `tax` de `10.5`.
## Actualizaciones parciales con `PATCH` { #partial-updates-with-patch }
## Actualizaciones parciales con `PATCH` { #partial-updates-with-patch }
También puedes usar la operación de <ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH"class="external-link"target="_blank">HTTP `PATCH`</a> para actualizar *parcialmente* datos.
También puedes usar la operación de [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) para actualizar *parcialmente* datos.
Esto significa que puedes enviar solo los datos que deseas actualizar, dejando el resto intacto.
Esto significa que puedes enviar solo los datos que deseas actualizar, dejando el resto intacto.
@ -95,6 +95,6 @@ Observa que el modelo de entrada sigue siendo validado.
Entonces, si deseas recibir actualizaciones parciales que puedan omitir todos los atributos, necesitas tener un modelo con todos los atributos marcados como opcionales (con valores por defecto o `None`).
Entonces, si deseas recibir actualizaciones parciales que puedan omitir todos los atributos, necesitas tener un modelo con todos los atributos marcados como opcionales (con valores por defecto o `None`).
Para distinguir entre los modelos con todos los valores opcionales para **actualizaciones** y modelos con valores requeridos para **creación**, puedes utilizar las ideas descritas en [Modelos Extra](extra-models.md){.internal-link target=_blank}.
Para distinguir entre los modelos con todos los valores opcionales para **actualizaciones** y modelos con valores requeridos para **creación**, puedes utilizar las ideas descritas en [Modelos Extra](extra-models.md).
@ -6,7 +6,7 @@ Un **request** body es un dato enviado por el cliente a tu API. Un **response**
Tu API casi siempre tiene que enviar un **response** body. Pero los clientes no necesariamente necesitan enviar **request bodies** todo el tiempo, a veces solo solicitan un path, quizás con algunos parámetros de query, pero no envían un body.
Tu API casi siempre tiene que enviar un **response** body. Pero los clientes no necesariamente necesitan enviar **request bodies** todo el tiempo, a veces solo solicitan un path, quizás con algunos parámetros de query, pero no envían un body.
Para declarar un **request** body, usas modelos de <ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic</a> con todo su poder y beneficios.
Para declarar un **request** body, usas modelos de [Pydantic](https://docs.pydantic.dev/) con todo su poder y beneficios.
/// info | Información
/// info | Información
@ -73,7 +73,7 @@ Con solo esa declaración de tipo en Python, **FastAPI** hará lo siguiente:
* Si los datos son inválidos, devolverá un error claro e indicado, señalando exactamente dónde y qué fue lo incorrecto.
* Si los datos son inválidos, devolverá un error claro e indicado, señalando exactamente dónde y qué fue lo incorrecto.
* Proporcionar los datos recibidos en el parámetro `item`.
* 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.
* 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 <ahref="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.
* Generar definiciones de [JSON Schema](https://json-schema.org) 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 <abbrtitle="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 <abbrtitle="User Interfaces - Interfaces de usuario">UIs</abbr> de documentación automática.
## Documentación automática { #automatic-docs }
## Documentación automática { #automatic-docs }
@ -102,15 +102,15 @@ Y fue rigurosamente probado en la fase de diseño, antes de cualquier implementa
Incluso se hicieron algunos cambios en Pydantic para admitir esto.
Incluso se hicieron algunos cambios en Pydantic para admitir esto.
Las capturas de pantalla anteriores se tomaron con <ahref="https://code.visualstudio.com"class="external-link"target="_blank">Visual Studio Code</a>.
Las capturas de pantalla anteriores se tomaron con [Visual Studio Code](https://code.visualstudio.com).
Pero obtendrías el mismo soporte en el editor con <ahref="https://www.jetbrains.com/pycharm/"class="external-link"target="_blank">PyCharm</a> y la mayoría de los otros editores de Python:
Pero obtendrías el mismo soporte en el editor con [PyCharm](https://www.jetbrains.com/pycharm/) y la mayoría de los otros editores de Python:
<imgsrc="/img/tutorial/body/image05.png">
<imgsrc="/img/tutorial/body/image05.png">
/// tip | Consejo
/// tip | Consejo
Si usas <ahref="https://www.jetbrains.com/pycharm/"class="external-link"target="_blank">PyCharm</a> como tu editor, puedes usar el <ahref="https://github.com/koxudaxi/pydantic-pycharm-plugin/"class="external-link"target="_blank">Pydantic PyCharm Plugin</a>.
Si usas [PyCharm](https://www.jetbrains.com/pycharm/) como tu editor, puedes usar el [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/).
Mejora el soporte del editor para modelos de Pydantic, con:
Mejora el soporte del editor para modelos de Pydantic, con:
@ -163,4 +163,4 @@ Pero agregar las anotaciones de tipos permitirá que tu editor te brinde un mejo
## Sin Pydantic { #without-pydantic }
## Sin Pydantic { #without-pydantic }
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}.
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).
# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }
# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }
<ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"class="external-link"target="_blank">CORS o "Cross-Origin Resource Sharing"</a> se refiere a situaciones en las que un frontend que se ejecuta en un navegador tiene código JavaScript que se comunica con un backend, y el backend está en un "origen" diferente al frontend.
[CORS o "Cross-Origin Resource Sharing"](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) se refiere a situaciones en las que un frontend que se ejecuta en un navegador tiene código JavaScript que se comunica con un backend, y el backend está en un "origen" diferente al frontend.
## Origen { #origin }
## Origen { #origin }
@ -56,10 +56,10 @@ Se admiten los siguientes argumentos:
* `allow_origins` - Una lista de orígenes que deberían estar permitidos para hacer requests cross-origin. Por ejemplo, `['https://example.org', 'https://www.example.org']`. Puedes usar `['*']` para permitir cualquier origen.
* `allow_origins` - Una lista de orígenes que deberían estar permitidos para hacer requests cross-origin. Por ejemplo, `['https://example.org', 'https://www.example.org']`. Puedes usar `['*']` para permitir cualquier origen.
* `allow_origin_regex` - Una cadena regex para coincidir con orígenes que deberían estar permitidos para hacer requests cross-origin. por ejemplo, `'https://.*\.example\.org'`.
* `allow_origin_regex` - Una cadena regex para coincidir con orígenes que deberían estar permitidos para hacer requests cross-origin. por ejemplo, `'https://.*\.example\.org'`.
* `allow_methods` - Una lista de métodos HTTP que deberían estar permitidos para requests cross-origin. Por defecto es `['GET']`. Puedes usar `['*']` para permitir todos los métodos estándar.
* `allow_methods` - Una lista de métodos HTTP que deberían estar permitidos para requests cross-origin. Por defecto es `['GET']`. Puedes usar `['*']` para permitir todos los métodos estándar.
* `allow_headers` - Una lista de headers de request HTTP que deberían estar soportados para requests cross-origin. Por defecto es `[]`. Puedes usar `['*']` para permitir todos los headers. Los headers `Accept`, `Accept-Language`, `Content-Language` y `Content-Type` siempre están permitidos para <ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests"class="external-link"rel="noopener"target="_blank">requests CORS simples</a>.
* `allow_headers` - Una lista de headers de request HTTP que deberían estar soportados para requests cross-origin. Por defecto es `[]`. Puedes usar `['*']` para permitir todos los headers. Los headers `Accept`, `Accept-Language`, `Content-Language` y `Content-Type` siempre están permitidos para [requests CORS simples](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).
* `allow_credentials` - Indica que las cookies deberían estar soportadas para requests cross-origin. Por defecto es `False`.
* `allow_credentials` - Indica que las cookies deberían estar soportadas para requests cross-origin. Por defecto es `False`.
Ninguno de `allow_origins`, `allow_methods` y `allow_headers` puede establecerse a `['*']` si `allow_credentials` está configurado a `True`. Todos deben ser <ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards"class="external-link"rel="noopener"target="_blank">especificados explícitamente</a>.
Ninguno de `allow_origins`, `allow_methods` y `allow_headers` puede establecerse a `['*']` si `allow_credentials` está configurado a `True`. Todos deben ser [especificados explícitamente](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards).
* `expose_headers` - Indica cualquier header de response que debería ser accesible para el navegador. Por defecto es `[]`.
* `expose_headers` - Indica cualquier header de response que debería ser accesible para el navegador. Por defecto es `[]`.
* `max_age` - Establece un tiempo máximo en segundos para que los navegadores almacenen en caché los responses CORS. Por defecto es `600`.
* `max_age` - Establece un tiempo máximo en segundos para que los navegadores almacenen en caché los responses CORS. Por defecto es `600`.
@ -78,7 +78,7 @@ Cualquier request con un header `Origin`. En este caso, el middleware pasará el
## Más info { #more-info }
## Más info { #more-info }
Para más información sobre <abbrtitle="Cross-Origin Resource Sharing">CORS</abbr>, revisa la <ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"class="external-link"target="_blank">documentación de CORS de Mozilla</a>.
Para más información sobre <abbrtitle="Cross-Origin Resource Sharing">CORS</abbr>, revisa la [documentación de CORS de Mozilla](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).
Para más información, revisa <ahref="https://docs.python.org/3/library/__main__.html"class="external-link"target="_blank">la documentación oficial de Python</a>.
Para más información, revisa [la documentación oficial de Python](https://docs.python.org/3/library/__main__.html).
@ -32,7 +32,7 @@ También puede ayudar a evitar confusiones para nuevos desarrolladores que vean
En este ejemplo usamos headers personalizados inventados `X-Key` y `X-Token`.
En este ejemplo usamos headers personalizados inventados `X-Key` y `X-Token`.
Pero en casos reales, al implementar seguridad, obtendrías más beneficios usando las [Utilidades de Seguridad integradas (el próximo capítulo)](../security/index.md){.internal-link target=_blank}.
Pero en casos reales, al implementar seguridad, obtendrías más beneficios usando las [Utilidades de Seguridad integradas (el próximo capítulo)](../security/index.md).
///
///
@ -62,7 +62,7 @@ Así que, puedes reutilizar una dependencia normal (que devuelve un valor) que y
## Dependencias para un grupo de *path operations* { #dependencies-for-a-group-of-path-operations }
## Dependencias para un grupo de *path operations* { #dependencies-for-a-group-of-path-operations }
Más adelante, cuando leas sobre cómo estructurar aplicaciones más grandes ([Aplicaciones Más Grandes - Múltiples Archivos](../../tutorial/bigger-applications.md){.internal-link target=_blank}), posiblemente con múltiples archivos, aprenderás cómo declarar un único parámetro `dependencies` para un grupo de *path operations*.
Más adelante, cuando leas sobre cómo estructurar aplicaciones más grandes ([Aplicaciones Más Grandes - Múltiples Archivos](../../tutorial/bigger-applications.md)), posiblemente con múltiples archivos, aprenderás cómo declarar un único parámetro `dependencies` para un grupo de *path operations*.
@ -14,8 +14,8 @@ Asegúrate de usar `yield` una sola vez por dependencia.
Cualquier función que sea válida para usar con:
Cualquier función que sea válida para usar con:
* <ahref="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager"class="external-link"target="_blank">`@contextlib.contextmanager`</a> o
* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) o
@ -87,7 +87,7 @@ Puedes tener cualquier combinación de dependencias que quieras.
/// note | Detalles técnicos
/// note | Detalles técnicos
Esto funciona gracias a los <ahref="https://docs.python.org/3/library/contextlib.html"class="external-link"target="_blank">Context Managers</a> de Python.
Esto funciona gracias a los [Context Managers](https://docs.python.org/3/library/contextlib.html) de Python.
**FastAPI** los utiliza internamente para lograr esto.
**FastAPI** los utiliza internamente para lograr esto.
@ -238,9 +238,9 @@ Si quieres ver qué ha cambiado en diferentes versiones de FastAPI, puedes leer
### Qué son los "Context Managers" { #what-are-context-managers }
### Qué son los "Context Managers" { #what-are-context-managers }
Los "Context Managers" son aquellos objetos de Python que puedes usar en una declaración`with`.
Los "Context Managers" son aquellos objetos de Python que puedes usar en un `with` statement.
Por ejemplo, <ahref="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files"class="external-link"target="_blank">puedes usar `with` para leer un archivo</a>:
Por ejemplo, [puedes usar `with` para leer un archivo](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):
```Python
```Python
with open("./somefile.txt") as f:
with open("./somefile.txt") as f:
@ -264,7 +264,7 @@ Si apenas estás comenzando con **FastAPI**, podrías querer omitirlo por ahora.
///
///
En Python, puedes crear Context Managers <ahref="https://docs.python.org/3/reference/datamodel.html#context-managers"class="external-link"target="_blank">creando una clase con dos métodos: `__enter__()` y `__exit__()`</a>.
En Python, puedes crear Context Managers [creando una clase con dos métodos: `__enter__()` y `__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers).
También puedes usarlos dentro de las dependencias de **FastAPI** con `yield` usando
También puedes usarlos dentro de las dependencias de **FastAPI** con `yield` usando
`with` o `async with` en la función de dependencia:
`with` o `async with` en la función de dependencia:
@ -275,8 +275,8 @@ También puedes usarlos dentro de las dependencias de **FastAPI** con `yield` us
Otra manera de crear un context manager es con:
Otra manera de crear un context manager es con:
* <ahref="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager"class="external-link"target="_blank">`@contextlib.contextmanager`</a> o
* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) o
Para algunos tipos de aplicaciones, podrías querer agregar dependencias a toda la aplicación.
Para algunos tipos de aplicaciones, podrías querer agregar dependencias a toda la aplicación.
Similar a como puedes [agregar `dependencies` a los *path operation decorators*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, puedes agregarlos a la aplicación de `FastAPI`.
Similar a como puedes [agregar `dependencies` a los *path operation decorators*](dependencies-in-path-operation-decorators.md), puedes agregarlos a la aplicación de `FastAPI`.
En ese caso, se aplicarán a todas las *path operations* en la aplicación:
En ese caso, se aplicarán a todas las *path operations* en la aplicación:
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.
Y todas las ideas en la sección sobre [agregar `dependencies` a los *path operation decorators*](dependencies-in-path-operation-decorators.md) siguen aplicándose, pero en este caso, a todas las *path operations* en la app.
## Dependencias para grupos de *path operations* { #dependencies-for-groups-of-path-operations }
## Dependencias para grupos de *path operations* { #dependencies-for-groups-of-path-operations }
Más adelante, al leer sobre cómo estructurar aplicaciones más grandes ([Aplicaciones Más Grandes - Múltiples Archivos](../../tutorial/bigger-applications.md){.internal-link target=_blank}), posiblemente con múltiples archivos, aprenderás cómo declarar un solo parámetro de `dependencies` para un grupo de *path operations*.
Más adelante, al leer sobre cómo estructurar aplicaciones más grandes ([Aplicaciones Más Grandes - Múltiples Archivos](../../tutorial/bigger-applications.md)), posiblemente con múltiples archivos, aprenderás cómo declarar un solo parámetro de `dependencies` para un grupo de *path operations*.
@ -57,7 +57,7 @@ FastAPI agregó soporte para `Annotated` (y comenzó a recomendarlo) en la versi
Si tienes una versión anterior, obtendrás errores al intentar usar `Annotated`.
Si tienes una versión anterior, obtendrás errores al intentar usar `Annotated`.
Asegúrate de [Actualizar la versión de FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} al menos a la 0.95.1 antes de usar `Annotated`.
Asegúrate de [Actualizar la versión de FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions) al menos a la 0.95.1 antes de usar `Annotated`.
///
///
@ -152,7 +152,7 @@ No importa. **FastAPI** sabrá qué hacer.
/// note | Nota
/// note | Nota
Si no lo sabes, revisa la sección [Async: *"¿Con prisa?"*](../../async.md#in-a-hurry){.internal-link target=_blank} sobre `async` y `await` en la documentación.
Si no lo sabes, revisa la sección [Async: *"¿Con prisa?"*](../../async.md#in-a-hurry) sobre `async` y `await` en la documentación.
@ -12,7 +12,7 @@ Imaginemos que tienes una base de datos `fake_db` que solo recibe datos compatib
Por ejemplo, no recibe objetos `datetime`, ya que no son compatibles con JSON.
Por ejemplo, no recibe objetos `datetime`, ya que no son compatibles con JSON.
Entonces, un objeto `datetime` tendría que ser convertido a un `str` que contenga los datos en <ahref="https://en.wikipedia.org/wiki/ISO_8601"class="external-link"target="_blank">formato ISO</a>.
Entonces, un objeto `datetime` tendría que ser convertido a un `str` que contenga los datos en [formato ISO](https://en.wikipedia.org/wiki/ISO_8601).
De la misma manera, esta base de datos no recibiría un modelo de Pydantic (un objeto con atributos), solo un `dict`.
De la misma manera, esta base de datos no recibiría un modelo de Pydantic (un objeto con atributos), solo un `dict`.
@ -24,7 +24,7 @@ Recibe un objeto, como un modelo de Pydantic, y devuelve una versión compatible
En este ejemplo, convertiría el modelo de Pydantic a un `dict`, y el `datetime` a un `str`.
En este ejemplo, convertiría el modelo de Pydantic a un `dict`, y el `datetime` a un `str`.
El resultado de llamarlo es algo que puede ser codificado con la función estándar de Python <ahref="https://docs.python.org/3/library/json.html#json.dumps"class="external-link"target="_blank">`json.dumps()`</a>.
El resultado de llamarlo es algo que puede ser codificado con la función estándar de Python [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps).
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.
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.
@ -36,7 +36,7 @@ Aquí hay algunos de los tipos de datos adicionales que puedes usar:
* `datetime.timedelta`:
* `datetime.timedelta`:
* Un `datetime.timedelta` de Python.
* Un `datetime.timedelta` de Python.
* En requests y responses se representará como un `float` de segundos totales.
* En requests y responses se representará como un `float` de segundos totales.
* Pydantic también permite representarlo como una "codificación de diferencia horaria ISO 8601", <ahref="https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers"class="external-link"target="_blank">consulta la documentación para más información</a>.
* Pydantic también permite representarlo como una "codificación de diferencia horaria ISO 8601", [consulta la documentación para más información](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).
* `frozenset`:
* `frozenset`:
* En requests y responses, tratado igual que un `set`:
* En requests y responses, tratado igual que un `set`:
* En requests, se leerá una list, eliminando duplicados y convirtiéndola en un `set`.
* En requests, se leerá una list, eliminando duplicados y convirtiéndola en un `set`.
@ -45,11 +45,11 @@ Aquí hay algunos de los tipos de datos adicionales que puedes usar:
* `bytes`:
* `bytes`:
* `bytes` estándar de Python.
* `bytes` estándar de Python.
* En requests y responses se tratará como `str`.
* En requests y responses se tratará como `str`.
* El esquema generado especificará que es un `str` con "binary" como "format".
* El esquema generado especificará que es un `str` con `binary` como "format".
* `Decimal`:
* `Decimal`:
* `Decimal` estándar de Python.
* `Decimal` estándar de Python.
* En requests y responses, manejado igual que un `float`.
* En requests y responses, manejado igual que un `float`.
* Puedes revisar todos los tipos de datos válidos de Pydantic aquí: <ahref="https://docs.pydantic.dev/latest/usage/types/types/"class="external-link"target="_blank">Tipos de datos de Pydantic</a>.
* Puedes revisar todos los tipos de datos válidos de Pydantic aquí: [Tipos de datos de Pydantic](https://docs.pydantic.dev/latest/usage/types/types/).
@ -12,7 +12,7 @@ Esto es especialmente el caso para los modelos de usuario, porque:
Nunca almacenes contraseñas de usuarios en texto plano. Siempre almacena un "hash seguro" que puedas verificar luego.
Nunca almacenes contraseñas de usuarios en texto plano. Siempre almacena un "hash seguro" que puedas verificar luego.
Si no lo sabes, aprenderás qué es un "hash de contraseña" en los [capítulos de seguridad](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.
Si no lo sabes, aprenderás qué es un "hash de contraseña" en los [capítulos de seguridad](security/simple-oauth2.md#password-hashing).
///
///
@ -162,11 +162,11 @@ Puedes declarar un response que sea la `Union` de dos o más tipos, eso signific
Se definirá en OpenAPI con `anyOf`.
Se definirá en OpenAPI con `anyOf`.
Para hacerlo, usa la anotación de tipos estándar de Python <ahref="https://docs.python.org/3/library/typing.html#typing.Union"class="external-link"target="_blank">`typing.Union`</a>:
Para hacerlo, usa la anotación de tipos estándar de Python [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union):
/// note | Nota
/// note | Nota
Al definir una <ahref="https://docs.pydantic.dev/latest/concepts/types/#unions"class="external-link"target="_blank">`Union`</a>, incluye el tipo más específico primero, seguido por el tipo menos específico. En el ejemplo a continuación, el más específico `PlaneItem` viene antes de `CarItem` en `Union[PlaneItem, CarItem]`.
Al definir una [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions), incluye el tipo más específico primero, seguido por el tipo menos específico. En el ejemplo a continuación, el más específico `PlaneItem` viene antes de `CarItem` en `Union[PlaneItem, CarItem]`.
<spanstyle="background-color:#009485"><fontcolor="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
<spanstyle="background-color:#009485"><fontcolor="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
@ -58,7 +58,7 @@ Esa línea muestra la URL donde tu aplicación está siendo servida, en tu máqu
### Revisa { #check-it }
### Revisa { #check-it }
Abre tu navegador en <ahref="http://127.0.0.1:8000"class="external-link"target="_blank">http://127.0.0.1:8000</a>.
Abre tu navegador en [http://127.0.0.1:8000](http://127.0.0.1:8000).
Verás el response JSON como:
Verás el response JSON como:
@ -68,17 +68,17 @@ Verás el response JSON como:
### Documentación interactiva de la API { #interactive-api-docs }
### Documentación interactiva de la API { #interactive-api-docs }
Ahora ve a <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a>.
Ahora ve a [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
Verás la documentación interactiva automática de la API (proporcionada por <ahref="https://github.com/swagger-api/swagger-ui"class="external-link"target="_blank">Swagger UI</a>):
Verás la documentación interactiva automática de la API (proporcionada por [Swagger UI](https://github.com/swagger-api/swagger-ui)):
### Documentación alternativa de la API { #alternative-api-docs }
### Documentación alternativa de la API { #alternative-api-docs }
Y ahora, ve a <ahref="http://127.0.0.1:8000/redoc"class="external-link"target="_blank">http://127.0.0.1:8000/redoc</a>.
Y ahora, ve a [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).
Verás la documentación alternativa automática (proporcionada por <ahref="https://github.com/Rebilly/ReDoc"class="external-link"target="_blank">ReDoc</a>):
Verás la documentación alternativa automática (proporcionada por [ReDoc](https://github.com/Rebilly/ReDoc)):
@ -92,7 +92,7 @@ Un "esquema" es una definición o descripción de algo. No el código que lo imp
#### Esquema de la API { #api-schema }
#### Esquema de la API { #api-schema }
En este caso, <ahref="https://github.com/OAI/OpenAPI-Specification"class="external-link"target="_blank">OpenAPI</a> es una especificación que dicta cómo definir un esquema de tu API.
En este caso, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) es una especificación que dicta cómo definir un esquema de tu API.
Esta definición de esquema incluye los paths de tu API, los posibles parámetros que toman, etc.
Esta definición de esquema incluye los paths de tu API, los posibles parámetros que toman, etc.
@ -110,7 +110,7 @@ OpenAPI define un esquema de API para tu API. Y ese esquema incluye definiciones
Si tienes curiosidad por cómo se ve el esquema OpenAPI en bruto, FastAPI automáticamente genera un JSON (esquema) con las descripciones de toda tu API.
Si tienes curiosidad por cómo se ve el esquema OpenAPI en bruto, FastAPI automáticamente genera un JSON (esquema) con las descripciones de toda tu API.
@ -143,9 +143,58 @@ Y hay docenas de alternativas, todas basadas en OpenAPI. Podrías añadir fácil
También podrías usarlo para generar código automáticamente, para clientes que se comuniquen con tu API. Por ejemplo, aplicaciones frontend, móviles o IoT.
También podrías usarlo para generar código automáticamente, para clientes que se comuniquen con tu API. Por ejemplo, aplicaciones frontend, móviles o IoT.
### Configura el `entrypoint` de la app en `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }
Puedes configurar dónde está tu app en un archivo `pyproject.toml` así:
```toml
[tool.fastapi]
entrypoint = "main:app"
```
Ese `entrypoint` le dirá al comando `fastapi` que debe hacer el import de la app así:
```python
from main import app
```
Si tu código estuviera estructurado así:
```
.
├── backend
│ ├── main.py
│ ├── __init__.py
```
Entonces pondrías el `entrypoint` como:
```toml
[tool.fastapi]
entrypoint = "backend.main:app"
```
lo cual sería equivalente a:
```python
from backend.main import app
```
### `fastapi dev` con path { #fastapi-dev-with-path }
También puedes pasar el path del archivo al comando `fastapi dev`, y adivinará el objeto app de FastAPI que debe usar:
```console
$ fastapi dev main.py
```
Pero tendrías que recordar pasar el path correcto cada vez que llames al comando `fastapi`.
Además, otras herramientas podrían no ser capaces de encontrarlo, por ejemplo la [Extensión de VS Code](../editor-support.md) o [FastAPI Cloud](https://fastapicloud.com), así que se recomienda usar el `entrypoint` en `pyproject.toml`.
### Despliega tu app (opcional) { #deploy-your-app-optional }
### Despliega tu app (opcional) { #deploy-your-app-optional }
Opcionalmente puedes desplegar tu app de FastAPI en <ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>, ve y únete a la lista de espera si aún no lo has hecho. 🚀
Opcionalmente puedes desplegar tu app de FastAPI en [FastAPI Cloud](https://fastapicloud.com), ve y únete a la lista de espera si aún no lo has hecho. 🚀
Si ya tienes una cuenta de **FastAPI Cloud** (te invitamos desde la lista de espera 😉), puedes desplegar tu aplicación con un solo comando.
Si ya tienes una cuenta de **FastAPI Cloud** (te invitamos desde la lista de espera 😉), puedes desplegar tu aplicación con un solo comando.
@ -191,7 +240,7 @@ Deploying to FastAPI Cloud...
`FastAPI` es una clase que hereda directamente de `Starlette`.
`FastAPI` es una clase que hereda directamente de `Starlette`.
Puedes usar toda la funcionalidad de <ahref="https://www.starlette.dev/"class="external-link"target="_blank">Starlette</a> con `FastAPI` también.
Puedes usar toda la funcionalidad de [Starlette](https://www.starlette.dev/) con `FastAPI` también.
///
///
@ -336,7 +385,7 @@ También podrías definirla como una función normal en lugar de `async def`:
/// note | Nota
/// note | Nota
Si no sabes la diferencia, Revisa la sección [Async: *"¿Tienes prisa?"*](../async.md#in-a-hurry){.internal-link target=_blank}.
Si no sabes la diferencia, Revisa la sección [Async: *"¿Tienes prisa?"*](../async.md#in-a-hurry).
///
///
@ -352,11 +401,11 @@ Hay muchos otros objetos y modelos que serán automáticamente convertidos a JSO
### Paso 6: Despliégalo { #step-6-deploy-it }
### Paso 6: Despliégalo { #step-6-deploy-it }
Despliega tu app en **<ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>** con un solo comando: `fastapi deploy`. 🎉
Despliega tu app en **[FastAPI Cloud](https://fastapicloud.com)** con un solo comando: `fastapi deploy`. 🎉
#### Sobre FastAPI Cloud { #about-fastapi-cloud }
#### Sobre FastAPI Cloud { #about-fastapi-cloud }
**<ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>** está construido por el mismo autor y equipo detrás de **FastAPI**.
**[FastAPI Cloud](https://fastapicloud.com)** está construido por el mismo autor y equipo detrás de **FastAPI**.
Agiliza el proceso de **construir**, **desplegar** y **acceder** a una API con el mínimo esfuerzo.
Agiliza el proceso de **construir**, **desplegar** y **acceder** a una API con el mínimo esfuerzo.
@ -81,7 +81,7 @@ Pero en caso de que los necesites para un escenario avanzado, puedes agregar hea
## Instalar manejadores de excepciones personalizados { #install-custom-exception-handlers }
## Instalar manejadores de excepciones personalizados { #install-custom-exception-handlers }
Puedes agregar manejadores de excepciones personalizados con <ahref="https://www.starlette.dev/exceptions/"class="external-link"target="_blank">las mismas utilidades de excepciones de Starlette</a>.
Puedes agregar manejadores de excepciones personalizados con [las mismas utilidades de excepciones de Starlette](https://www.starlette.dev/exceptions/).
Supongamos que tienes una excepción personalizada `UnicornException` que tú (o un paquete que usas) podrías lanzar.
Supongamos que tienes una excepción personalizada `UnicornException` que tú (o un paquete que usas) podrías lanzar.
Cuando instalas con `pip install "fastapi[standard]"` viene con algunas dependencias opcionales estándar por defecto, incluyendo `fastapi-cloud-cli`, que te permite hacer deploy a <ahref="https://fastapicloud.com"class="external-link"target="_blank">FastAPI Cloud</a>.
Cuando instalas con `pip install "fastapi[standard]"` viene con algunas dependencias opcionales estándar por defecto, incluyendo `fastapi-cloud-cli`, que te permite hacer deploy a [FastAPI Cloud](https://fastapicloud.com).
Si no quieres tener esas dependencias opcionales, en su lugar puedes instalar `pip install fastapi`.
Si no quieres tener esas dependencias opcionales, en su lugar puedes instalar `pip install fastapi`.
@ -84,6 +84,12 @@ Si quieres instalar las dependencias estándar pero sin `fastapi-cloud-cli`, pue
///
///
/// tip | Consejo
FastAPI tiene una [extensión oficial para VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (y Cursor), que ofrece muchas funcionalidades, incluyendo un explorador de path operation, búsqueda de path operation, navegación de CodeLens en tests (saltar a la definición desde tests), y deploy y logs de FastAPI Cloud, todo desde tu editor.
///
## Guía Avanzada del Usuario { #advanced-user-guide }
## Guía Avanzada del Usuario { #advanced-user-guide }
También hay una **Guía Avanzada del Usuario** que puedes leer después de esta **Tutorial - Guía del Usuario**.
También hay una **Guía Avanzada del Usuario** que puedes leer después de esta **Tutorial - Guía del Usuario**.
@ -15,7 +15,7 @@ Un "middleware" es una función que trabaja con cada **request** antes de que se
Si tienes dependencias con `yield`, el código de salida se ejecutará *después* del middleware.
Si tienes dependencias con `yield`, el código de salida se ejecutará *después* del middleware.
Si hubiera tareas en segundo plano (cubiertas en la sección [Tareas en segundo plano](background-tasks.md){.internal-link target=_blank}, lo verás más adelante), se ejecutarán *después* de todo el middleware.
Si hubiera tareas en segundo plano (cubiertas en la sección [Tareas en segundo plano](background-tasks.md), lo verás más adelante), se ejecutarán *después* de todo el middleware.
///
///
@ -35,9 +35,9 @@ La función middleware recibe:
/// tip | Consejo
/// tip | Consejo
Ten en cuenta que los custom proprietary headers se pueden añadir <ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers"class="external-link"target="_blank">usando el prefijo `X-`</a>.
Ten en cuenta que los custom proprietary headers se pueden añadir [usando el prefijo `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).
Pero si tienes custom headers que deseas que un cliente en un navegador pueda ver, necesitas añadirlos a tus configuraciones de CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) usando el parámetro `expose_headers` documentado en <ahref="https://www.starlette.dev/middleware/#corsmiddleware"class="external-link"target="_blank">la documentación de CORS de Starlette</a>.
Pero si tienes custom headers que deseas que un cliente en un navegador pueda ver, necesitas añadirlos a tus configuraciones de CORS ([CORS (Cross-Origin Resource Sharing)](cors.md)) usando el parámetro `expose_headers` documentado en [la documentación de CORS de Starlette](https://www.starlette.dev/middleware/#corsmiddleware).
///
///
@ -61,7 +61,7 @@ Por ejemplo, podrías añadir un custom header `X-Process-Time` que contenga el
/// tip | Consejo
/// tip | Consejo
Aquí usamos <ahref="https://docs.python.org/3/library/time.html#time.perf_counter"class="external-link"target="_blank">`time.perf_counter()`</a> en lugar de `time.time()` porque puede ser más preciso para estos casos de uso. 🤓
Aquí usamos [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) en lugar de `time.time()` porque puede ser más preciso para estos casos de uso. 🤓
///
///
@ -90,6 +90,6 @@ Este comportamiento de apilamiento asegura que los middlewares se ejecuten en un
## Otros middlewares { #other-middlewares }
## Otros middlewares { #other-middlewares }
Más adelante puedes leer sobre otros middlewares en la [Guía del Usuario Avanzado: Middleware Avanzado](../advanced/middleware.md){.internal-link target=_blank}.
Más adelante puedes leer sobre otros middlewares en la [Guía del Usuario Avanzado: Middleware Avanzado](../advanced/middleware.md).
Leerás sobre cómo manejar <abbrtitle="Cross-Origin Resource Sharing">CORS</abbr> con un middleware en la siguiente sección.
Leerás sobre cómo manejar <abbrtitle="Cross-Origin Resource Sharing">CORS</abbr> con un middleware en la siguiente sección.
@ -58,7 +58,7 @@ Puedes añadir un `summary` y `description`:
Como las descripciones tienden a ser largas y cubrir múltiples líneas, puedes declarar la descripción de la *path operation* en la <dfntitle="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í.
Como las descripciones tienden a ser largas y cubrir múltiples líneas, puedes declarar la descripción de la *path operation* en la <dfntitle="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 <ahref="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).
Puedes escribir [Markdown](https://en.wikipedia.org/wiki/Markdown) en el docstring, se interpretará y mostrará correctamente (teniendo en cuenta la indentación del docstring).
@ -14,7 +14,7 @@ FastAPI agregó soporte para `Annotated` (y comenzó a recomendar su uso) en la
Si tienes una versión anterior, obtendrás errores al intentar usar `Annotated`.
Si tienes una versión anterior, obtendrás errores al intentar usar `Annotated`.
Asegúrate de [Actualizar la versión de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} a al menos la 0.95.1 antes de usar `Annotated`.
Asegúrate de [Actualizar la versión de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) a al menos la 0.95.1 antes de usar `Annotated`.
///
///
@ -122,7 +122,7 @@ Y lo mismo para <abbr title="less than - menor que"><code>lt</code></abbr>.
## Resumen { #recap }
## Resumen { #recap }
Con `Query`, `Path` (y otros que aún no has visto) puedes declarar metadatos y validaciones de string de las mismas maneras que con [Parámetros de Query y Validaciones de String](query-params-str-validations.md){.internal-link target=_blank}.
Con `Query`, `Path` (y otros que aún no has visto) puedes declarar metadatos y validaciones de string de las mismas maneras que con [Parámetros de Query y Validaciones de String](query-params-str-validations.md).
@ -6,7 +6,7 @@ Puedes declarar "parámetros" o "variables" de path con la misma sintaxis que se
El valor del parámetro de path `item_id` se pasará a tu función como el argumento `item_id`.
El valor del parámetro de path `item_id` se pasará a tu función como el argumento `item_id`.
Así que, si ejecutas este ejemplo y vas a <ahref="http://127.0.0.1:8000/items/foo"class="external-link"target="_blank">http://127.0.0.1:8000/items/foo</a>, verás un response de:
Así que, si ejecutas este ejemplo y vas a [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), verás un response de:
```JSON
```JSON
{"item_id":"foo"}
{"item_id":"foo"}
@ -28,7 +28,7 @@ Esto te dará soporte del editor dentro de tu función, con chequeo de errores,
## <dfntitle="también conocido como: serialización, parsing, marshalling">Conversión</dfn> de datos { #data-conversion }
## <dfntitle="también conocido como: serialización, parsing, marshalling">Conversión</dfn> de datos { #data-conversion }
Si ejecutas este ejemplo y abres tu navegador en <ahref="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:
Si ejecutas este ejemplo y abres tu navegador en [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3), verás un response de:
```JSON
```JSON
{"item_id":3}
{"item_id":3}
@ -44,7 +44,7 @@ Entonces, con esa declaración de tipo, **FastAPI** te ofrece <dfn title="conver
## Validación de datos { #data-validation }
## Validación de datos { #data-validation }
Pero si vas al navegador en <ahref="http://127.0.0.1:8000/items/foo"class="external-link"target="_blank">http://127.0.0.1:8000/items/foo</a>, verás un bonito error HTTP de:
Pero si vas al navegador en [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), verás un bonito error HTTP de:
```JSON
```JSON
{
{
@ -64,7 +64,7 @@ Pero si vas al navegador en <a href="http://127.0.0.1:8000/items/foo" class="ext
porque el parámetro de path `item_id` tenía un valor de `"foo"`, que no es un `int`.
porque el parámetro de path `item_id` tenía un valor de `"foo"`, que no es un `int`.
El mismo error aparecería si proporcionaras un `float` en lugar de un `int`, como en: <ahref="http://127.0.0.1:8000/items/4.2"class="external-link"target="_blank">http://127.0.0.1:8000/items/4.2</a>
El mismo error aparecería si proporcionaras un `float` en lugar de un `int`, como en: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)
/// check | Revisa
/// check | Revisa
@ -78,7 +78,7 @@ Esto es increíblemente útil mientras desarrollas y depuras código que interac
## Documentación { #documentation }
## Documentación { #documentation }
Y cuando abras tu navegador en <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a>, verás una documentación de API automática e interactiva como:
Y cuando abras tu navegador en [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), verás una documentación de API automática e interactiva como:
<imgsrc="/img/tutorial/path-params/image01.png">
<imgsrc="/img/tutorial/path-params/image01.png">
@ -92,9 +92,9 @@ Nota que el parámetro de path está declarado como un entero.
## Beneficios basados en estándares, documentación alternativa { #standards-based-benefits-alternative-documentation }
## Beneficios basados en estándares, documentación alternativa { #standards-based-benefits-alternative-documentation }
Y porque el esquema generado es del estándar <ahref="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md"class="external-link"target="_blank">OpenAPI</a>, hay muchas herramientas compatibles.
Y porque el esquema generado es del estándar [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md), hay muchas herramientas compatibles.
Debido a esto, el propio **FastAPI** proporciona una documentación de API alternativa (usando ReDoc), a la cual puedes acceder en <ahref="http://127.0.0.1:8000/redoc"class="external-link"target="_blank">http://127.0.0.1:8000/redoc</a>:
Debido a esto, el propio **FastAPI** proporciona una documentación de API alternativa (usando ReDoc), a la cual puedes acceder en [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc):
<imgsrc="/img/tutorial/path-params/image02.png">
<imgsrc="/img/tutorial/path-params/image02.png">
@ -102,7 +102,7 @@ De la misma manera, hay muchas herramientas compatibles. Incluyendo herramientas
## Pydantic { #pydantic }
## Pydantic { #pydantic }
Toda la validación de datos se realiza internamente con <ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic</a>, así que obtienes todos los beneficios de esta. Y sabes que estás en buenas manos.
Toda la validación de datos se realiza internamente con [Pydantic](https://docs.pydantic.dev/), así que obtienes todos los beneficios de esta. Y sabes que estás en buenas manos.
Puedes usar las mismas declaraciones de tipo con `str`, `float`, `bool` y muchos otros tipos de datos complejos.
Puedes usar las mismas declaraciones de tipo con `str`, `float`, `bool` y muchos otros tipos de datos complejos.
@ -35,13 +35,13 @@ FastAPI añadió soporte para `Annotated` (y empezó a recomendarlo) en la versi
Si tienes una versión más antigua, obtendrás errores al intentar usar `Annotated`.
Si tienes una versión más antigua, obtendrás errores al intentar usar `Annotated`.
Asegúrate de [Actualizar la versión de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} a al menos 0.95.1 antes de usar `Annotated`.
Asegúrate de [Actualizar la versión de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) a al menos 0.95.1 antes de usar `Annotated`.
///
///
## Usar `Annotated` en el tipo del parámetro `q` { #use-annotated-in-the-type-for-the-q-parameter }
## Usar `Annotated` en el tipo del parámetro `q` { #use-annotated-in-the-type-for-the-q-parameter }
¿Recuerdas que te dije antes que `Annotated` puede usarse para agregar metadatos a tus parámetros en la [Introducción a Tipos de Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
¿Recuerdas que te dije antes que `Annotated` puede usarse para agregar metadatos a tus parámetros en la [Introducción a Tipos de Python](../python-types.md#type-hints-with-metadata-annotations)?
Ahora es el momento de usarlo con FastAPI. 🚀
Ahora es el momento de usarlo con FastAPI. 🚀
@ -158,7 +158,7 @@ Podrías llamar a esa misma función en otros lugares sin FastAPI, y funcionarí
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 <ahref="https://typer.tiangolo.com/"class="external-link"target="_blank">Typer</a>. 🚀
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 [Typer](https://typer.tiangolo.com/). 🚀
## Agregar más validaciones { #add-more-validations }
## Agregar más validaciones { #add-more-validations }
@ -296,9 +296,9 @@ También puedes usar `list` directamente en lugar de `list[str]`:
/// note | Nota
/// note | Nota
Ten en cuenta que en este caso, FastAPI no comprobará el contenido de la lista.
Ten en cuenta que en este caso, FastAPI no comprobará el contenido de la list.
Por ejemplo, `list[int]` comprobaría (y documentaría) que el contenido de la lista son enteros. Pero `list` sola no lo haría.
Por ejemplo, `list[int]` comprobaría (y documentaría) que el contenido de la list son enteros. Pero `list` sola no lo haría.
///
///
@ -370,11 +370,11 @@ Podría haber casos donde necesites hacer alguna validación personalizada que n
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 <ahref="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator"class="external-link"target="_blank">`AfterValidator` de Pydantic</a> dentro de `Annotated`.
Puedes lograr eso usando [`AfterValidator` de Pydantic](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) dentro de `Annotated`.
/// tip | Consejo
/// tip | Consejo
Pydantic también tiene <ahref="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator"class="external-link"target="_blank">`BeforeValidator`</a> y otros. 🤓
Pydantic también tiene [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) y otros. 🤓
@ -4,9 +4,9 @@ Puedes definir archivos que serán subidos por el cliente utilizando `File`.
/// info | Información
/// info | Información
Para recibir archivos subidos, primero instala <ahref="https://github.com/Kludex/python-multipart"class="external-link"target="_blank">`python-multipart`</a>.
Para recibir archivos subidos, primero instala [`python-multipart`](https://github.com/Kludex/python-multipart).
Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalarlo, por ejemplo:
Asegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo y luego instalarlo, por ejemplo:
```console
```console
$ pip install python-multipart
$ pip install python-multipart
@ -63,8 +63,8 @@ Usar `UploadFile` tiene varias ventajas sobre `bytes`:
* Un archivo almacenado en memoria hasta un límite de tamaño máximo, y después de superar este límite, se almacenará en el disco.
* Un archivo almacenado en memoria hasta un límite de tamaño máximo, y después de superar este límite, se almacenará en el disco.
* Esto significa que funcionará bien para archivos grandes como imágenes, videos, binarios grandes, etc. sin consumir toda la memoria.
* Esto significa que funcionará bien para archivos grandes como imágenes, videos, binarios grandes, etc. sin consumir toda la memoria.
* Puedes obtener metadatos del archivo subido.
* Puedes obtener metadatos del archivo subido.
* Tiene una interfaz `async`<ahref="https://docs.python.org/3/glossary.html#term-file-like-object"class="external-link"target="_blank">parecida a un archivo</a>.
* Tiene una interfaz `async`[parecida a un archivo](https://docs.python.org/3/glossary.html#term-file-like-object).
* Expone un objeto Python real <ahref="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile"class="external-link"target="_blank">`SpooledTemporaryFile`</a> que puedes pasar directamente a otros paquetes que esperan un objeto parecido a un archivo.
* Expone un objeto Python real [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) que puedes pasar directamente a otros paquetes que esperan un objeto parecido a un archivo.
### `UploadFile` { #uploadfile }
### `UploadFile` { #uploadfile }
@ -72,7 +72,7 @@ Usar `UploadFile` tiene varias ventajas sobre `bytes`:
* `filename`: Un `str` con el nombre original del archivo que fue subido (por ejemplo, `myimage.jpg`).
* `filename`: Un `str` con el nombre original del archivo que fue subido (por ejemplo, `myimage.jpg`).
* `content_type`: Un `str` con el tipo de contenido (MIME type / media type) (por ejemplo, `image/jpeg`).
* `content_type`: Un `str` con el tipo de contenido (MIME type / media type) (por ejemplo, `image/jpeg`).
* `file`: Un <ahref="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile"class="external-link"target="_blank">`SpooledTemporaryFile`</a> (un objeto <ahref="https://docs.python.org/3/glossary.html#term-file-like-object"class="external-link"target="_blank">parecido a un archivo</a>). Este es el objeto de archivo Python real que puedes pasar directamente a otras funciones o paquetes que esperan un objeto "parecido a un archivo".
* `file`: Un [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (un objeto [parecido a un archivo](https://docs.python.org/3/glossary.html#term-file-like-object)). Este es el objeto de archivo Python real que puedes pasar directamente a otras funciones o paquetes que esperan un objeto "parecido a un archivo".
`UploadFile` tiene los siguientes métodos `async`. Todos ellos llaman a los métodos correspondientes del archivo por debajo (usando el `SpooledTemporaryFile` interno).
`UploadFile` tiene los siguientes métodos `async`. Todos ellos llaman a los métodos correspondientes del archivo por debajo (usando el `SpooledTemporaryFile` interno).
@ -111,7 +111,7 @@ El `UploadFile` de **FastAPI** hereda directamente del `UploadFile` de **Starlet
## Qué es "Form Data" { #what-is-form-data }
## Qué es "Form Data" { #what-is-form-data }
La manera en que los forms de HTML (`<form></form>`) envían los datos al servidor normalmente utiliza una codificación "especial" para esos datos, es diferente de JSON.
La manera en que los formularios de HTML (`<form></form>`) envían los datos al servidor normalmente utiliza una codificación "especial" para esos datos, es diferente de JSON.
**FastAPI** se asegurará de leer esos datos del lugar correcto en lugar de JSON.
**FastAPI** se asegurará de leer esos datos del lugar correcto en lugar de JSON.
@ -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.
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 <ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST"class="external-link"target="_blank"><abbrtitle="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 [<abbr title="Mozilla Developer Network - Red de Desarrolladores de Mozilla">MDN</abbr> web docs para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
@ -4,9 +4,9 @@ Puedes definir archivos y campos de formulario al mismo tiempo usando `File` y `
/// info | Información
/// info | Información
Para recibir archivos subidos y/o form data, primero instala <ahref="https://github.com/Kludex/python-multipart"class="external-link"target="_blank">`python-multipart`</a>.
Para recibir archivos subidos y/o form data, primero instala [`python-multipart`](https://github.com/Kludex/python-multipart).
Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, actívalo y luego instálalo, por ejemplo:
Asegúrate de crear un [entorno virtual](../virtual-environments.md), actívalo y luego instálalo, por ejemplo:
@ -4,9 +4,9 @@ Cuando necesitas recibir campos de formulario en lugar de JSON, puedes usar `For
/// info | Información
/// info | Información
Para usar formularios, primero instala <ahref="https://github.com/Kludex/python-multipart"class="external-link"target="_blank">`python-multipart`</a>.
Para usar formularios, primero instala [`python-multipart`](https://github.com/Kludex/python-multipart).
Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo, y luego instalarlo, por ejemplo:
Asegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo, y luego instalarlo, por ejemplo:
```console
```console
$ pip install python-multipart
$ pip install python-multipart
@ -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.
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<ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST"class="external-link"target="_blank"><abbrtitle="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 las [<abbr title="Mozilla Developer Network - Red de Desarrolladores de Mozilla">MDN</abbr> web docs para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
@ -13,6 +13,7 @@ FastAPI usará este tipo de retorno para:
* Agregar un **JSON Schema** para el response, en la *path operation* de OpenAPI.
* Agregar un **JSON Schema** para el response, en la *path operation* de OpenAPI.
* Esto será utilizado por la **documentación automática**.
* Esto será utilizado por la **documentación automática**.
* También será utilizado por herramientas de generación automática de código de cliente.
* También será utilizado por herramientas de generación automática de código de cliente.
* **Serializar** los datos devueltos a JSON usando Pydantic, que está escrito en **Rust**, por lo que será **mucho más rápido**.
Pero lo más importante:
Pero lo más importante:
@ -73,9 +74,9 @@ Aquí estamos declarando un modelo `UserIn`, contendrá una contraseña en texto
/// info | Información
/// info | Información
Para usar `EmailStr`, primero instala <ahref="https://github.com/JoshData/python-email-validator"class="external-link"target="_blank">`email-validator`</a>.
Para usar `EmailStr`, primero instala [`email-validator`](https://github.com/JoshData/python-email-validator).
Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo, y luego instalarlo, por ejemplo:
Asegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo, y luego instalarlo, por ejemplo:
```console
```console
$ pip install email-validator
$ pip install email-validator
@ -181,7 +182,7 @@ Podría haber casos en los que devuelvas algo que no es un campo válido de Pyda
### Devolver un Response Directamente { #return-a-response-directly }
### Devolver un Response Directamente { #return-a-response-directly }
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}.
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).
como se describe en <ahref="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict"class="external-link"target="_blank">la documentación de Pydantic</a> para `exclude_defaults` y `exclude_none`.
como se describe en [la documentación de Pydantic](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) para `exclude_defaults` y `exclude_none`.
@ -20,7 +20,7 @@ El parámetro `status_code` recibe un número con el código de estado HTTP.
/// info | Información
/// info | Información
`status_code` también puede recibir un `IntEnum`, como por ejemplo el <ahref="https://docs.python.org/3/library/http.html#http.HTTPStatus"class="external-link"target="_blank">`http.HTTPStatus`</a> de Python.
`status_code` también puede recibir un `IntEnum`, como por ejemplo el [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus) de Python.
///
///
@ -66,7 +66,7 @@ En breve:
/// tip | Consejo
/// tip | Consejo
Para saber más sobre cada código de estado y qué código es para qué, revisa la <ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status"class="external-link"target="_blank">documentación de <abbrtitle="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 [documentación de <abbr title="Mozilla Developer Network - Red de Desarrolladores de Mozilla">MDN</abbr> sobre códigos de estado HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).
## Cambiando el valor por defecto { #changing-the-default }
## Cambiando el valor por defecto { #changing-the-default }
Más adelante, en la [Guía de Usuario Avanzada](../advanced/response-change-status-code.md){.internal-link target=_blank}, verás cómo devolver un código de estado diferente al valor por defecto que estás declarando aquí.
Más adelante, en la [Guía de Usuario Avanzada](../advanced/response-change-status-code.md), verás cómo devolver un código de estado diferente al valor por defecto que estás declarando aquí.
# Declarar Ejemplos de Request { #declare-request-example-data }
# Declarar Datos de Ejemplo de Request { #declare-request-example-data }
Puedes declarar ejemplos de los datos que tu aplicación puede recibir.
Puedes declarar ejemplos de los datos que tu aplicación puede recibir.
@ -12,7 +12,7 @@ Puedes declarar `examples` para un modelo de Pydantic que se añadirá al JSON S
Esa información extra se añadirá tal cual al **JSON Schema** resultante para ese modelo, y se usará en la documentación de la API.
Esa información extra se añadirá tal cual al **JSON Schema** resultante para ese modelo, y se usará en la documentación de la API.
Puedes usar el atributo `model_config` que toma un `dict` como se describe en <ahref="https://docs.pydantic.dev/latest/api/config/"class="external-link"target="_blank">la documentación de Pydantic: Configuración</a>.
Puedes usar el atributo `model_config` que toma un `dict` como se describe en [Documentación de Pydantic: Configuración](https://docs.pydantic.dev/latest/api/config/).
Puedes establecer `"json_schema_extra"` con un `dict` que contenga cualquier dato adicional que te gustaría que aparezca en el JSON Schema generado, incluyendo `examples`.
Puedes establecer `"json_schema_extra"` con un `dict` que contenga cualquier dato adicional que te gustaría que aparezca en el JSON Schema generado, incluyendo `examples`.
@ -145,12 +145,12 @@ JSON Schema no tenía `examples`, así que OpenAPI añadió su propio campo `exa
OpenAPI también añadió los campos `example` y `examples` a otras partes de la especificación:
OpenAPI también añadió los campos `example` y `examples` a otras partes de la especificación:
* <ahref="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object"class="external-link"target="_blank">`Parameter Object` (en la especificación)</a> que era usado por FastAPI:
* [`Parameter Object` (en la especificación)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object) que era usado por FastAPI:
* `Path()`
* `Path()`
* `Query()`
* `Query()`
* `Header()`
* `Header()`
* `Cookie()`
* `Cookie()`
* <ahref="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object"class="external-link"target="_blank">`Request Body Object`, en el campo `content`, sobre el `Media Type Object` (en la especificación)</a> que era usado por FastAPI:
* [`Request Body Object`, en el campo `content`, sobre el `Media Type Object` (en la especificación)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object) que era usado por FastAPI:
* `Body()`
* `Body()`
* `File()`
* `File()`
* `Form()`
* `Form()`
@ -163,7 +163,7 @@ Este viejo parámetro `examples` específico de OpenAPI ahora es `openapi_exampl
### Campo `examples` de JSON Schema { #json-schemas-examples-field }
### Campo `examples` de JSON Schema { #json-schemas-examples-field }
Pero luego JSON Schema añadió un <ahref="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5"class="external-link"target="_blank">campo `examples`</a> a una nueva versión de la especificación.
Pero luego JSON Schema añadió un [campo `examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) a una nueva versión de la especificación.
Y entonces el nuevo OpenAPI 3.1.0 se basó en la última versión (JSON Schema 2020-12) que incluía este nuevo campo `examples`.
Y entonces el nuevo OpenAPI 3.1.0 se basó en la última versión (JSON Schema 2020-12) que incluía este nuevo campo `examples`.
@ -26,11 +26,11 @@ Copia el ejemplo en un archivo `main.py`:
/// info | Información
/// info | Información
El paquete <ahref="https://github.com/Kludex/python-multipart"class="external-link"target="_blank">`python-multipart`</a> se instala automáticamente con **FastAPI** cuando ejecutas el comando `pip install "fastapi[standard]"`.
El paquete [`python-multipart`](https://github.com/Kludex/python-multipart) se instala automáticamente con **FastAPI** cuando ejecutas el comando `pip install "fastapi[standard]"`.
Sin embargo, si usas el comando `pip install fastapi`, el paquete `python-multipart` no se incluye por defecto.
Sin embargo, si usas el comando `pip install fastapi`, el paquete `python-multipart` no se incluye por defecto.
Para instalarlo manualmente, asegúrate de crear un [entorno virtual](../../virtual-environments.md){.internal-link target=_blank}, activarlo, y luego instalarlo con:
Para instalarlo manualmente, asegúrate de crear un [entorno virtual](../../virtual-environments.md), activarlo, y luego instalarlo con:
```console
```console
$ pip install python-multipart
$ pip install python-multipart
@ -45,7 +45,7 @@ Ejecuta el ejemplo con:
<divclass="termy">
<divclass="termy">
```console
```console
$ fastapi dev main.py
$ fastapi dev
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
```
@ -54,7 +54,7 @@ $ fastapi dev main.py
## Revisa { #check-it }
## Revisa { #check-it }
Ve a la documentación interactiva en: <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a>.
Ve a la documentación interactiva en: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
Verás algo así:
Verás algo así:
@ -140,7 +140,7 @@ Aquí `tokenUrl="token"` se refiere a una URL relativa `token` que aún no hemos
Porque estamos usando una URL relativa, si tu API estuviera ubicada en `https://example.com/`, entonces se referiría a `https://example.com/token`. Pero si tu API estuviera ubicada en `https://example.com/api/v1/`, entonces se referiría a `https://example.com/api/v1/token`.
Porque estamos usando una URL relativa, si tu API estuviera ubicada en `https://example.com/`, entonces se referiría a `https://example.com/token`. Pero si tu API estuviera ubicada en `https://example.com/api/v1/`, entonces se referiría a `https://example.com/api/v1/token`.
Usar una URL relativa es importante para asegurarse de que tu aplicación siga funcionando incluso en un caso de uso avanzado como [Detrás de un Proxy](../../advanced/behind-a-proxy.md){.internal-link target=_blank}.
Usar una URL relativa es importante para asegurarse de que tu aplicación siga funcionando incluso en un caso de uso avanzado como [Detrás de un Proxy](../../advanced/behind-a-proxy.md).
@ -24,13 +24,13 @@ De esta manera, puedes crear un token con una expiración de, digamos, 1 semana.
Después de una semana, el token estará expirado y el usuario no estará autorizado y tendrá que iniciar sesión nuevamente para obtener un nuevo token. Y si el usuario (o un tercero) intenta modificar el token para cambiar la expiración, podrás descubrirlo, porque las firmas no coincidirían.
Después de una semana, el token estará expirado y el usuario no estará autorizado y tendrá que iniciar sesión nuevamente para obtener un nuevo token. Y si el usuario (o un tercero) intenta modificar el token para cambiar la expiración, podrás descubrirlo, porque las firmas no coincidirían.
Si quieres jugar con tokens JWT y ver cómo funcionan, revisa <ahref="https://jwt.io/"class="external-link"target="_blank">https://jwt.io</a>.
Si quieres jugar con tokens JWT y ver cómo funcionan, revisa [https://jwt.io](https://jwt.io/).
## Instalar `PyJWT` { #install-pyjwt }
## Instalar `PyJWT` { #install-pyjwt }
Necesitamos instalar `PyJWT` para generar y verificar los tokens JWT en Python.
Necesitamos instalar `PyJWT` para generar y verificar los tokens JWT en Python.
Asegúrate de crear un [entorno virtual](../../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalar `pyjwt`:
Asegúrate de crear un [entorno virtual](../../virtual-environments.md), activarlo y luego instalar `pyjwt`:
<divclass="termy">
<divclass="termy">
@ -46,7 +46,7 @@ $ pip install pyjwt
Si planeas usar algoritmos de firma digital como RSA o ECDSA, deberías instalar la dependencia del paquete de criptografía `pyjwt[crypto]`.
Si planeas usar algoritmos de firma digital como RSA o ECDSA, deberías instalar la dependencia del paquete de criptografía `pyjwt[crypto]`.
Puedes leer más al respecto en la <ahref="https://pyjwt.readthedocs.io/en/latest/installation.html"class="external-link"target="_blank">documentación de instalación de PyJWT</a>.
Puedes leer más al respecto en la [documentación de instalación de PyJWT](https://pyjwt.readthedocs.io/en/latest/installation.html).
///
///
@ -72,7 +72,7 @@ Soporta muchos algoritmos de hashing seguros y utilidades para trabajar con ello
El algoritmo recomendado es "Argon2".
El algoritmo recomendado es "Argon2".
Asegúrate de crear un [entorno virtual](../../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalar pwdlib con Argon2:
Asegúrate de crear un [entorno virtual](../../virtual-environments.md), activarlo y luego instalar pwdlib con Argon2:
<divclass="termy">
<divclass="termy">
@ -200,7 +200,7 @@ Lo importante a tener en cuenta es que la clave `sub` debería tener un identifi
## Revisa { #check-it }
## Revisa { #check-it }
Ejecuta el servidor y ve a la documentación: <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a>.
Ejecuta el servidor y ve a la documentación: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
**FastAPI** no requiere que uses una base de datos SQL (relacional). Pero puedes utilizar **cualquier base de datos** que desees.
**FastAPI** no requiere que uses una base de datos SQL (relacional). Pero puedes utilizar **cualquier base de datos** que desees.
Aquí veremos un ejemplo usando <ahref="https://sqlmodel.tiangolo.com/"class="external-link"target="_blank">SQLModel</a>.
Aquí veremos un ejemplo usando [SQLModel](https://sqlmodel.tiangolo.com/).
**SQLModel** está construido sobre <ahref="https://www.sqlalchemy.org/"class="external-link"target="_blank">SQLAlchemy</a> y Pydantic. Fue creado por el mismo autor de **FastAPI** para ser la combinación perfecta para aplicaciones de FastAPI que necesiten usar **bases de datos SQL**.
**SQLModel** está construido sobre [SQLAlchemy](https://www.sqlalchemy.org/) y Pydantic. Fue creado por el mismo autor de **FastAPI** para ser la combinación perfecta para aplicaciones de FastAPI que necesiten usar **bases de datos SQL**.
/// tip | Consejo
/// tip | Consejo
@ -26,15 +26,15 @@ Más adelante, para tu aplicación en producción, es posible que desees usar un
/// tip | Consejo
/// tip | Consejo
Hay un generador de proyectos oficial con **FastAPI** y **PostgreSQL** que incluye un frontend y más herramientas: <ahref="https://github.com/fastapi/full-stack-fastapi-template"class="external-link"target="_blank">https://github.com/fastapi/full-stack-fastapi-template</a>
Hay un generador de proyectos oficial con **FastAPI** y **PostgreSQL** que incluye un frontend y más herramientas: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)
///
///
Este es un tutorial muy simple y corto, si deseas aprender sobre bases de datos en general, sobre SQL o más funcionalidades avanzadas, ve a la <ahref="https://sqlmodel.tiangolo.com/"class="external-link"target="_blank">documentación de SQLModel</a>.
Este es un tutorial muy simple y corto, si deseas aprender sobre bases de datos en general, sobre SQL o más funcionalidades avanzadas, ve a la [documentación de SQLModel](https://sqlmodel.tiangolo.com/).
## Instalar `SQLModel` { #install-sqlmodel }
## Instalar `SQLModel` { #install-sqlmodel }
Primero, asegúrate de crear tu [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, actívalo, y luego instala `sqlmodel`:
Primero, asegúrate de crear tu [entorno virtual](../virtual-environments.md), actívalo, y luego instala `sqlmodel`:
<divclass="termy">
<divclass="termy">
@ -65,7 +65,7 @@ Hay algunas diferencias:
* `Field(primary_key=True)` le dice a SQLModel que `id` es la **clave primaria** en la base de datos SQL (puedes aprender más sobre claves primarias de SQL en la documentación de SQLModel).
* `Field(primary_key=True)` le dice a SQLModel que `id` es la **clave primaria** en la base de datos SQL (puedes aprender más sobre claves primarias de SQL en la documentación de SQLModel).
Nota: Usamos `int | None` para el campo de clave primaria para que en el código Python podamos *crear un objeto sin un `id`* (`id=None`), asumiendo que la base de datos lo *generará al guardar*. SQLModel entiende que la base de datos proporcionará el `id` y *define la columna como un `INTEGER` no nulo* en el esquema de la base de datos. Consulta la <ahref="https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id"class="external-link"target="_blank">documentación de SQLModel sobre claves primarias</a> para más detalles.
Nota: Usamos `int | None` para el campo de clave primaria para que en el código Python podamos *crear un objeto sin un `id`* (`id=None`), asumiendo que la base de datos lo *generará al guardar*. SQLModel entiende que la base de datos proporcionará el `id` y *define la columna como un `INTEGER` no nulo* en el esquema de la base de datos. Consulta la [documentación de SQLModel sobre claves primarias](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) para más detalles.
* `Field(index=True)` le dice a SQLModel que debe crear un **índice SQL** para esta columna, lo que permitirá búsquedas más rápidas en la base de datos cuando se lean datos filtrados por esta columna.
* `Field(index=True)` le dice a SQLModel que debe crear un **índice SQL** para esta columna, lo que permitirá búsquedas más rápidas en la base de datos cuando se lean datos filtrados por esta columna.
@ -111,7 +111,7 @@ Para producción probablemente usarías un script de migración que se ejecuta a
/// tip | Consejo
/// tip | Consejo
SQLModel tendrá utilidades de migración envolviendo Alembic, pero por ahora, puedes usar <ahref="https://alembic.sqlalchemy.org/en/latest/"class="external-link"target="_blank">Alembic</a> directamente.
SQLModel tendrá utilidades de migración envolviendo Alembic, pero por ahora, puedes usar [Alembic](https://alembic.sqlalchemy.org/en/latest/) directamente.
///
///
@ -152,7 +152,7 @@ Puedes ejecutar la aplicación:
<divclass="termy">
<divclass="termy">
```console
```console
$ fastapi dev main.py
$ fastapi dev
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
```
@ -337,7 +337,7 @@ Puedes ejecutar la aplicación de nuevo:
<divclass="termy">
<divclass="termy">
```console
```console
$ fastapi dev main.py
$ fastapi dev
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
```
@ -352,6 +352,6 @@ Si vas a la interfaz de `/docs` de la API, verás que ahora está actualizada, y
## Resumen { #recap }
## Resumen { #recap }
Puedes usar <ahref="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 usar [**SQLModel**](https://sqlmodel.tiangolo.com/) 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 <ahref="https://sqlmodel.tiangolo.com/tutorial/fastapi/"class="external-link"target="_blank">tutorial más largo sobre el uso de SQLModel con **FastAPI**</a>. 🚀
Puedes aprender mucho más en la documentación de **SQLModel**, hay un mini [tutorial más largo sobre el uso de SQLModel con **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/). 🚀
Esto es diferente a usar un `APIRouter`, ya que una aplicación montada es completamente independiente. El OpenAPI y la documentación de tu aplicación principal no incluirán nada de la aplicación montada, etc.
Esto es diferente a usar un `APIRouter`, ya que una aplicación montada es completamente independiente. El OpenAPI y la documentación de tu aplicación principal no incluirán nada de la aplicación montada, etc.
Puedes leer más sobre esto en la [Guía de Usuario Avanzada](../advanced/index.md){.internal-link target=_blank}.
Puedes leer más sobre esto en la [Guía de Usuario Avanzada](../advanced/index.md).
## Detalles { #details }
## Detalles { #details }
@ -37,4 +37,4 @@ Todos estos parámetros pueden ser diferentes a "`static`", ajústalos según la
## Más info { #more-info }
## Más info { #more-info }
Para más detalles y opciones revisa <ahref="https://www.starlette.dev/staticfiles/"class="external-link"target="_blank">la documentación de Starlette sobre Archivos Estáticos</a>.
Para más detalles y opciones revisa [la documentación de Starlette sobre Archivos Estáticos](https://www.starlette.dev/staticfiles/).
Gracias a <ahref="https://www.starlette.dev/testclient/"class="external-link"target="_blank">Starlette</a>, escribir pruebas para aplicaciones de **FastAPI** es fácil y agradable.
Gracias a [Starlette](https://www.starlette.dev/testclient/), escribir pruebas para aplicaciones de **FastAPI** es fácil y agradable.
Está basado en <ahref="https://www.python-httpx.org"class="external-link"target="_blank">HTTPX</a>, que a su vez está diseñado basado en Requests, por lo que es muy familiar e intuitivo.
Está basado en [HTTPX](https://www.python-httpx.org), que a su vez está diseñado basado en Requests, por lo que es muy familiar e intuitivo.
Con él, puedes usar <ahref="https://docs.pytest.org/"class="external-link"target="_blank">pytest</a> directamente con **FastAPI**.
Con él, puedes usar [pytest](https://docs.pytest.org/) directamente con **FastAPI**.
## Usando `TestClient` { #using-testclient }
## Usando `TestClient` { #using-testclient }
/// info | Información
/// info | Información
Para usar `TestClient`, primero instala <ahref="https://www.python-httpx.org"class="external-link"target="_blank">`httpx`</a>.
Para usar `TestClient`, primero instala [`httpx`](https://www.python-httpx.org).
Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalarlo, por ejemplo:
Asegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo y luego instalarlo, por ejemplo:
```console
```console
$ pip install httpx
$ pip install httpx
@ -42,7 +42,7 @@ Esto te permite usar `pytest` directamente sin complicaciones.
///
///
/// note | Nota Técnica
/// note | Detalles técnicos
También podrías usar `from starlette.testclient import TestClient`.
También podrías usar `from starlette.testclient import TestClient`.
Si quieres llamar a funciones `async` en tus pruebas además de enviar requests a tu aplicación FastAPI (por ejemplo, funciones asincrónicas de bases de datos), echa un vistazo a las [Pruebas Asincrónicas](../advanced/async-tests.md){.internal-link target=_blank} en el tutorial avanzado.
Si quieres llamar a funciones `async` en tus pruebas además de enviar requests a tu aplicación FastAPI (por ejemplo, funciones asincrónicas de bases de datos), echa un vistazo a las [Pruebas Asincrónicas](../advanced/async-tests.md) en el tutorial avanzado.
///
///
@ -64,7 +64,7 @@ Y tu aplicación de **FastAPI** también podría estar compuesta de varios archi
### Archivo de aplicación **FastAPI** { #fastapi-app-file }
### Archivo de aplicación **FastAPI** { #fastapi-app-file }
Digamos que tienes una estructura de archivos como se describe en [Aplicaciones Más Grandes](bigger-applications.md){.internal-link target=_blank}:
Digamos que tienes una estructura de archivos como se describe en [Aplicaciones Más Grandes](bigger-applications.md):
```
```
.
.
@ -75,6 +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**:
En el archivo `main.py` tienes tu aplicación de **FastAPI**:
* Para pasar *headers*, usa un `dict` en el parámetro `headers`.
* Para pasar *headers*, usa un `dict` en el parámetro `headers`.
* Para *cookies*, un `dict` en el parámetro `cookies`.
* Para *cookies*, un `dict` en el parámetro `cookies`.
Para más información sobre cómo pasar datos al backend (usando `httpx` o el `TestClient`) revisa la <ahref="https://www.python-httpx.org"class="external-link"target="_blank">documentación de HTTPX</a>.
Para más información sobre cómo pasar datos al backend (usando `httpx` o el `TestClient`) revisa la [documentación de HTTPX](https://www.python-httpx.org).
/// info | Información
/// info | Información
Ten en cuenta que el `TestClient` recibe datos que pueden ser convertidos a JSON, no modelos de Pydantic.
Ten en cuenta que el `TestClient` recibe datos que pueden ser convertidos a JSON, no modelos de Pydantic.
Si tienes un modelo de Pydantic en tu prueba y quieres enviar sus datos a la aplicación durante las pruebas, puedes usar el `jsonable_encoder` descrito en [Codificador Compatible con JSON](encoder.md){.internal-link target=_blank}.
Si tienes un modelo de Pydantic en tu prueba y quieres enviar sus datos a la aplicación durante las pruebas, puedes usar el `jsonable_encoder` descrito en [Codificador Compatible con JSON](encoder.md).
///
///
@ -153,7 +154,7 @@ Si tienes un modelo de Pydantic en tu prueba y quieres enviar sus datos a la apl
Después de eso, solo necesitas instalar `pytest`.
Después de eso, solo necesitas instalar `pytest`.
Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalarlo, por ejemplo:
Asegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo y luego instalarlo, por ejemplo: