Sync fastapi docs from eba8942c on 2026-04-11

This commit is contained in:
The Librarian
2026-04-11 04:00:10 +00:00
parent 18a95756ed
commit dea80f32eb
1157 changed files with 15132 additions and 8307 deletions
@@ -243,5 +243,5 @@ Por ejemplo:
Para ver exactamente qué puedes incluir en los responses, puedes revisar estas secciones en la especificación OpenAPI:
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object" class="external-link" target="_blank">Objeto de Responses de OpenAPI</a>, incluye el `Response Object`.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object" class="external-link" target="_blank">Objeto de Response de OpenAPI</a>, puedes incluir cualquier cosa de esto directamente en cada response dentro de tu parámetro `responses`. Incluyendo `description`, `headers`, `content` (dentro de este es que declaras diferentes media types y JSON Schemas), y `links`.
* [Objeto de Responses de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), incluye el `Response Object`.
* [Objeto de Response de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), puedes incluir cualquier cosa de esto directamente en cada response dentro de tu parámetro `responses`. Incluyendo `description`, `headers`, `content` (dentro de este es que declaras diferentes media types y JSON Schemas), y `links`.
@@ -38,4 +38,4 @@ También podrías usar `from starlette.responses import JSONResponse`.
Si devuelves códigos de estado adicionales y responses directamente, no se incluirán en el esquema de OpenAPI (la documentación de la API), porque FastAPI no tiene una forma de saber de antemano qué vas a devolver.
Pero puedes documentarlo en tu código, usando: [Responses Adicionales](additional-responses.md){.internal-link target=_blank}.
Pero puedes documentarlo en tu código, usando: [Responses Adicionales](additional-responses.md).
@@ -132,7 +132,7 @@ Si tienes este caso de uso específico usando SQLModel (o SQLAlchemy), podrías
De esa manera la sesión liberaría la conexión a la base de datos, para que otras requests puedan usarla.
Si tienes un caso de uso diferente que necesite salir temprano desde una dependencia con `yield`, por favor crea una <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">Pregunta de Discusión en GitHub</a> con tu caso de uso específico y por qué te beneficiaría tener cierre temprano para dependencias con `yield`.
Si tienes un caso de uso diferente que necesite salir temprano desde una dependencia con `yield`, por favor crea una [Pregunta de Discusión en GitHub](https://github.com/fastapi/fastapi/discussions/new?category=questions) con tu caso de uso específico y por qué te beneficiaría tener cierre temprano para dependencias con `yield`.
Si hay casos de uso convincentes para el cierre temprano en dependencias con `yield`, consideraría agregar una nueva forma de optar por el cierre temprano.
@@ -144,7 +144,7 @@ Esto cambió en la versión 0.110.0 para arreglar consumo de memoria no manejado
### Tareas en segundo plano y dependencias con `yield`, detalles técnicos { #background-tasks-and-dependencies-with-yield-technical-details }
Antes de FastAPI 0.106.0, elevar excepciones después de `yield` no era posible, el código de salida en dependencias con `yield` se ejecutaba después de que la response era enviada, por lo que [Manejadores de Excepciones](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} ya habrían corrido.
Antes de FastAPI 0.106.0, elevar excepciones después de `yield` no era posible, el código de salida en dependencias con `yield` se ejecutaba después de que la response era enviada, por lo que [Manejadores de Excepciones](../tutorial/handling-errors.md#install-custom-exception-handlers) ya habrían corrido.
Esto se diseñó así principalmente para permitir usar los mismos objetos devueltos con `yield` por las dependencias dentro de tareas en segundo plano, porque el código de salida se ejecutaría después de que las tareas en segundo plano terminaran.
+4 -4
View File
@@ -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` está basado en <a href="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 }
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
Si tu aplicación depende de eventos de lifespan, el `AsyncClient` no activará estos eventos. Para asegurarte de que se activen, usa `LifespanManager` de <a href="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
Si encuentras un `RuntimeError: Task attached to a different loop` al integrar llamadas a funciones asíncronas en tus tests (por ejemplo, cuando usas <a href="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")`.
///
+13 -13
View File
@@ -16,9 +16,9 @@ Pero por seguridad, como el server no sabe que está detrás de un proxy confiab
Los headers del proxy son:
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)
* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)
* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)
///
@@ -60,7 +60,7 @@ https://mysuperapp.com/items/
/// tip | Consejo
Si quieres aprender más sobre HTTPS, revisa la guía [Acerca de HTTPS](../deployment/https.md){.internal-link target=_blank}.
Si quieres aprender más sobre HTTPS, revisa la guía [Acerca de HTTPS](../deployment/https.md).
///
@@ -228,7 +228,7 @@ Pasar el `root_path` a `FastAPI` sería el equivalente a pasar la opción de lí
Ten en cuenta que el servidor (Uvicorn) no usará ese `root_path` para nada, a excepción de pasárselo a la app.
Pero si vas con tu navegador a <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a> verás el response normal:
Pero si vas con tu navegador a [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app) verás el response normal:
```JSON
{
@@ -251,9 +251,9 @@ En un caso así (sin un prefijo de path eliminado), el proxy escucharía algo co
## Probando localmente con Traefik { #testing-locally-with-traefik }
Puedes ejecutar fácilmente el experimento localmente con un prefijo de path eliminado usando <a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a>.
Puedes ejecutar fácilmente el experimento localmente con un prefijo de path eliminado usando [Traefik](https://docs.traefik.io/).
<a href="https://github.com/containous/traefik/releases" class="external-link" target="_blank">Descarga Traefik</a>, es un archivo binario único, puedes extraer el archivo comprimido y ejecutarlo directamente desde la terminal.
[Descarga Traefik](https://github.com/containous/traefik/releases), es un archivo binario único, puedes extraer el archivo comprimido y ejecutarlo directamente desde la terminal.
Luego crea un archivo `traefik.toml` con:
@@ -330,7 +330,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
### Revisa los responses { #check-the-responses }
Ahora, si vas a la URL con el puerto para Uvicorn: <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a>, verás el response normal:
Ahora, si vas a la URL con el puerto para Uvicorn: [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), verás el response normal:
```JSON
{
@@ -345,7 +345,7 @@ Nota que incluso aunque estés accediendo en `http://127.0.0.1:8000/app`, muestr
///
Y ahora abre la URL con el puerto para Traefik, incluyendo el prefijo de path: <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/app</a>.
Y ahora abre la URL con el puerto para Traefik, incluyendo el prefijo de path: [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).
Obtenemos el mismo response:
@@ -370,13 +370,13 @@ Pero aquí está la parte divertida. ✨
La forma "oficial" de acceder a la app sería a través del proxy con el prefijo de path que definimos. Así que, como esperaríamos, si intentas usar la UI de los docs servida por Uvicorn directamente, sin el prefijo de path en la URL, no funcionará, porque espera ser accedida a través del proxy.
Puedes verificarlo en <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>:
Puedes verificarlo en [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs):
<img src="/img/tutorial/behind-a-proxy/image01.png">
Pero si accedemos a la UI de los docs en la URL "oficial" usando el proxy con puerto `9999`, en `/api/v1/docs`, ¡funciona correctamente! 🎉
Puedes verificarlo en <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>:
Puedes verificarlo en [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs):
<img src="/img/tutorial/behind-a-proxy/image02.png">
@@ -433,7 +433,7 @@ Observa el server auto-generado con un valor `url` de `/api/v1`, tomado del `roo
///
En la UI de los docs en <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a> se vería como:
En la UI de los docs en [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) se vería como:
<img src="/img/tutorial/behind-a-proxy/image03.png">
@@ -461,6 +461,6 @@ y entonces no lo incluirá en el esquema de OpenAPI.
## Montando una sub-aplicación { #mounting-a-sub-application }
Si necesitas montar una sub-aplicación (como se describe en [Aplicaciones secundarias - Monturas](sub-applications.md){.internal-link target=_blank}) mientras usas un proxy con `root_path`, puedes hacerlo normalmente, como esperarías.
Si necesitas montar una sub-aplicación (como se describe en [Aplicaciones secundarias - Monturas](sub-applications.md)) mientras usas un proxy con `root_path`, puedes hacerlo normalmente, como esperarías.
FastAPI usará internamente el `root_path` de manera inteligente, así que simplemente funcionará. ✨
+36 -75
View File
@@ -1,8 +1,8 @@
# Response Personalizado - HTML, Stream, Archivo, otros { #custom-response-html-stream-file-others }
Por defecto, **FastAPI** devolverá los responses usando `JSONResponse`.
Por defecto, **FastAPI** devolverá responses JSON.
Puedes sobrescribirlo devolviendo un `Response` directamente como se ve en [Devolver una Response directamente](response-directly.md){.internal-link target=_blank}.
Puedes sobrescribirlo devolviendo un `Response` directamente como se ve en [Devolver una Response directamente](response-directly.md).
Pero si devuelves un `Response` directamente (o cualquier subclase, como `JSONResponse`), los datos no se convertirán automáticamente (incluso si declaras un `response_model`), y la documentación no se generará automáticamente (por ejemplo, incluyendo el "media type" específico, en el HTTP header `Content-Type` como parte del OpenAPI generado).
@@ -10,43 +10,27 @@ Pero también puedes declarar el `Response` que quieres usar (por ejemplo, cualq
Los contenidos que devuelvas desde tu *path operation function* se colocarán dentro de esa `Response`.
Y si ese `Response` tiene un media type JSON (`application/json`), como es el caso con `JSONResponse` y `UJSONResponse`, los datos que devuelvas se convertirán automáticamente (y serán filtrados) con cualquier `response_model` de Pydantic que hayas declarado en el *path operation decorator*.
/// note | Nota
Si usas una clase de response sin media type, FastAPI esperará que tu response no tenga contenido, por lo que no documentará el formato del response en su OpenAPI generado.
///
## Usa `ORJSONResponse` { #use-orjsonresponse }
## Responses JSON { #json-responses }
Por ejemplo, si estás exprimendo el rendimiento, puedes instalar y usar <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> y establecer el response como `ORJSONResponse`.
Por defecto FastAPI devuelve responses JSON.
Importa la clase `Response` (sub-clase) que quieras usar y declárala en el *path operation decorator*.
Si declaras un [Response Model](../tutorial/response-model.md) FastAPI lo usará para serializar los datos a JSON, usando Pydantic.
Para responses grandes, devolver una `Response` directamente es mucho más rápido que devolver un diccionario.
Si no declaras un response model, FastAPI usará el `jsonable_encoder` explicado en [Codificador Compatible con JSON](../tutorial/encoder.md) y lo pondrá en un `JSONResponse`.
Esto se debe a que, por defecto, FastAPI inspeccionará cada elemento dentro y se asegurará de que sea serializable como JSON, usando el mismo [Codificador Compatible con JSON](../tutorial/encoder.md){.internal-link target=_blank} explicado en el tutorial. Esto es lo que te permite devolver **objetos arbitrarios**, por ejemplo, modelos de bases de datos.
Si declaras un `response_class` con un media type JSON (`application/json`), como es el caso con `JSONResponse`, los datos que devuelvas se convertirán automáticamente (y serán filtrados) con cualquier `response_model` de Pydantic que hayas declarado en el *path operation decorator*. Pero los datos no se serializarán a bytes JSON con Pydantic, en su lugar se convertirán con el `jsonable_encoder` y luego se pasarán a la clase `JSONResponse`, que los serializará a bytes usando la librería JSON estándar de Python.
Pero si estás seguro de que el contenido que estás devolviendo es **serializable con JSON**, puedes pasarlo directamente a la clase de response y evitar la sobrecarga extra que FastAPI tendría al pasar tu contenido de retorno a través de `jsonable_encoder` antes de pasarlo a la clase de response.
### Rendimiento JSON { #json-performance }
{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
En resumen, si quieres el máximo rendimiento, usa un [Response Model](../tutorial/response-model.md) y no declares un `response_class` en el *path operation decorator*.
/// info | Información
El parámetro `response_class` también se utilizará para definir el "media type" del response.
En este caso, el HTTP header `Content-Type` se establecerá en `application/json`.
Y se documentará así en OpenAPI.
///
/// tip | Consejo
El `ORJSONResponse` solo está disponible en FastAPI, no en Starlette.
///
{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}
## Response HTML { #html-response }
@@ -69,7 +53,7 @@ Y se documentará así en OpenAPI.
### Devuelve una `Response` { #return-a-response }
Como se ve en [Devolver una Response directamente](response-directly.md){.internal-link target=_blank}, también puedes sobrescribir el response directamente en tu *path operation*, devolviéndolo.
Como se ve en [Devolver una Response directamente](response-directly.md), también puedes sobrescribir el response directamente en tu *path operation*, devolviéndolo.
El mismo ejemplo de arriba, devolviendo una `HTMLResponse`, podría verse así:
@@ -154,37 +138,11 @@ Toma algunos datos y devuelve un response codificado como `application/json`.
Este es el response usado por defecto en **FastAPI**, como leíste arriba.
### `ORJSONResponse` { #orjsonresponse }
/// note | Nota Técnica
Un response JSON rápido alternativo usando <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>, como leíste arriba.
Pero si declaras un response model o un tipo de retorno, eso se usará directamente para serializar los datos a JSON, y se devolverá directamente un response con el media type correcto para JSON, sin usar la clase `JSONResponse`.
/// info | Información
Esto requiere instalar `orjson`, por ejemplo, con `pip install orjson`.
///
### `UJSONResponse` { #ujsonresponse }
Un response JSON alternativo usando <a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>.
/// info | Información
Esto requiere instalar `ujson`, por ejemplo, con `pip install ujson`.
///
/// warning | Advertencia
`ujson` es menos cuidadoso que la implementación integrada de Python en cómo maneja algunos casos extremos.
///
{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
/// tip | Consejo
Es posible que `ORJSONResponse` sea una alternativa más rápida.
Esta es la forma ideal de obtener el mejor rendimiento.
///
@@ -200,6 +158,7 @@ Puedes devolver un `RedirectResponse` directamente:
O puedes usarlo en el parámetro `response_class`:
{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
Si haces eso, entonces puedes devolver la URL directamente desde tu *path operation* function.
@@ -214,31 +173,25 @@ También puedes usar el parámetro `status_code` combinado con el parámetro `re
### `StreamingResponse` { #streamingresponse }
Toma un generador `async` o un generador/iterador normal y transmite el cuerpo del response.
Toma un generador `async` o un generador/iterador normal (una función con `yield`) y transmite el cuerpo del response.
{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}
#### Usando `StreamingResponse` con objetos similares a archivos { #using-streamingresponse-with-file-like-objects }
/// note | Nota Técnica
Si tienes un <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">objeto similar a un archivo</a> (por ejemplo, el objeto devuelto por `open()`), puedes crear una función generadora para iterar sobre ese objeto similar a un archivo.
Una tarea `async` solo puede cancelarse cuando llega a un `await`. Si no hay `await`, el generador (función con `yield`) no se puede cancelar correctamente y puede seguir ejecutándose incluso después de solicitar la cancelación.
De esa manera, no tienes que leerlo todo primero en memoria, y puedes pasar esa función generadora al `StreamingResponse`, y devolverlo.
Como este pequeño ejemplo no necesita ninguna sentencia `await`, añadimos un `await anyio.sleep(0)` para darle al loop de eventos la oportunidad de manejar la cancelación.
Esto incluye muchos paquetes para interactuar con almacenamiento en la nube, procesamiento de video y otros.
Esto sería aún más importante con streams grandes o infinitos.
{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
1. Esta es la función generadora. Es una "función generadora" porque contiene declaraciones `yield` dentro.
2. Al usar un bloque `with`, nos aseguramos de que el objeto similar a un archivo se cierre después de que la función generadora termine. Así, después de que termina de enviar el response.
3. Este `yield from` le dice a la función que itere sobre esa cosa llamada `file_like`. Y luego, para cada parte iterada, yield esa parte como proveniente de esta función generadora (`iterfile`).
Entonces, es una función generadora que transfiere el trabajo de "generar" a algo más internamente.
Al hacerlo de esta manera, podemos ponerlo en un bloque `with`, y de esa manera, asegurarnos de que el objeto similar a un archivo se cierre después de finalizar.
///
/// tip | Consejo
Nota que aquí como estamos usando `open()` estándar que no admite `async` y `await`, declaramos el path operation con `def` normal.
En lugar de devolver un `StreamingResponse` directamente, probablemente deberías seguir el estilo en [Stream Data](./stream-data.md), es mucho más conveniente y maneja la cancelación por detrás de escena por ti.
Si estás transmitiendo JSON Lines, sigue el tutorial [Stream JSON Lines](../tutorial/stream-json-lines.md).
///
@@ -267,7 +220,7 @@ En este caso, puedes devolver la path del archivo directamente desde tu *path op
Puedes crear tu propia clase de response personalizada, heredando de `Response` y usándola.
Por ejemplo, digamos que quieres usar <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>, pero con algunas configuraciones personalizadas no utilizadas en la clase `ORJSONResponse` incluida.
Por ejemplo, digamos que quieres usar [`orjson`](https://github.com/ijl/orjson) con algunas configuraciones.
Digamos que quieres que devuelva JSON con sangría y formato, por lo que quieres usar la opción de orjson `orjson.OPT_INDENT_2`.
@@ -291,13 +244,21 @@ Ahora en lugar de devolver:
Por supuesto, probablemente encontrarás formas mucho mejores de aprovechar esto que formatear JSON. 😉
### `orjson` o Response Model { #orjson-or-response-model }
Si lo que buscas es rendimiento, probablemente te convenga más usar un [Response Model](../tutorial/response-model.md) que un response con `orjson`.
Con un response model, FastAPI usará Pydantic para serializar los datos a JSON, sin pasos intermedios, como convertirlos con `jsonable_encoder`, que ocurriría en cualquier otro caso.
Y por debajo, Pydantic usa los mismos mecanismos en Rust que `orjson` para serializar a JSON, así que ya obtendrás el mejor rendimiento con un response model.
## Clase de response por defecto { #default-response-class }
Al crear una instance de la clase **FastAPI** o un `APIRouter`, puedes especificar qué clase de response usar por defecto.
El parámetro que define esto es `default_response_class`.
En el ejemplo a continuación, **FastAPI** usará `ORJSONResponse` por defecto, en todas las *path operations*, en lugar de `JSONResponse`.
En el ejemplo a continuación, **FastAPI** usará `HTMLResponse` por defecto, en todas las *path operations*, en lugar de JSON.
{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
@@ -309,4 +270,4 @@ Todavía puedes sobrescribir `response_class` en *path operations* como antes.
## Documentación adicional { #additional-documentation }
También puedes declarar el media type y muchos otros detalles en OpenAPI usando `responses`: [Responses Adicionales en OpenAPI](additional-responses.md){.internal-link target=_blank}.
También puedes declarar el media type y muchos otros detalles en OpenAPI usando `responses`: [Responses Adicionales en OpenAPI](additional-responses.md).
+4 -4
View File
@@ -2,11 +2,11 @@
FastAPI está construido sobre **Pydantic**, y te he estado mostrando cómo usar modelos de Pydantic para declarar requests y responses.
Pero FastAPI también soporta el uso de <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> de la misma manera:
Pero FastAPI también soporta el uso de [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) de la misma manera:
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
Esto sigue siendo soportado gracias a **Pydantic**, ya que tiene <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">soporte interno para `dataclasses`</a>.
Esto sigue siendo soportado gracias a **Pydantic**, ya que tiene [soporte interno para `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).
Así que, incluso con el código anterior que no usa Pydantic explícitamente, FastAPI está usando Pydantic para convertir esos dataclasses estándar en su propia versión de dataclasses de Pydantic.
@@ -74,7 +74,7 @@ En ese caso, simplemente puedes intercambiar los `dataclasses` estándar con `py
Como siempre, en FastAPI puedes combinar `def` y `async def` según sea necesario.
Si necesitas un repaso sobre cuándo usar cuál, revisa la sección _"¿Con prisa?"_ en la documentación sobre [`async` y `await`](../async.md#in-a-hurry){.internal-link target=_blank}.
Si necesitas un repaso sobre cuándo usar cuál, revisa la sección _"¿Con prisa?"_ en la documentación sobre [`async` y `await`](../async.md#in-a-hurry).
9. Esta *path operation function* no está devolviendo dataclasses (aunque podría), sino una lista de diccionarios con datos internos.
@@ -88,7 +88,7 @@ Revisa las anotaciones en el código arriba para ver más detalles específicos.
También puedes combinar `dataclasses` con otros modelos de Pydantic, heredar de ellos, incluirlos en tus propios modelos, etc.
Para saber más, revisa la <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/" class="external-link" target="_blank">documentación de Pydantic sobre dataclasses</a>.
Para saber más, revisa la [documentación de Pydantic sobre dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/).
## Versión { #version }
+3 -3
View File
@@ -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. 🤓
Por debajo, en la especificación técnica ASGI, esto es parte del <a href="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
Puedes leer más sobre los manejadores `lifespan` de Starlette en <a href="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.
@@ -162,4 +162,4 @@ Incluyendo cómo manejar el estado de lifespan que puede ser usado en otras áre
## 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).
+8 -8
View File
@@ -8,11 +8,11 @@ En esta guía, aprenderás a generar un **SDK de TypeScript** para tu backend co
## Generadores de SDKs de código abierto { #open-source-sdk-generators }
Una opción versátil es el <a href="https://openapi-generator.tech/" class="external-link" target="_blank">OpenAPI Generator</a>, que soporta **muchos lenguajes de programación** y puede generar SDKs a partir de tu especificación OpenAPI.
Una opción versátil es el [OpenAPI Generator](https://openapi-generator.tech/), que soporta **muchos lenguajes de programación** y puede generar SDKs a partir de tu especificación OpenAPI.
Para **clientes de TypeScript**, <a href="https://heyapi.dev/" class="external-link" target="_blank">Hey API</a> es una solución diseñada específicamente, que ofrece una experiencia optimizada para el ecosistema de TypeScript.
Para **clientes de TypeScript**, [Hey API](https://heyapi.dev/) es una solución diseñada específicamente, que ofrece una experiencia optimizada para el ecosistema de TypeScript.
Puedes descubrir más generadores de SDK en <a href="https://openapi.tools/#sdk" class="external-link" target="_blank">OpenAPI.Tools</a>.
Puedes descubrir más generadores de SDK en [OpenAPI.Tools](https://openapi.tools/#sdk).
/// tip | Consejo
@@ -24,15 +24,15 @@ FastAPI genera automáticamente especificaciones **OpenAPI 3.1**, así que cualq
Esta sección destaca soluciones **respaldadas por empresas** y **venture-backed** de compañías que sponsorean FastAPI. Estos productos ofrecen **funcionalidades adicionales** e **integraciones** además de SDKs generados de alta calidad.
Al ✨ [**sponsorear FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, estas compañías ayudan a asegurar que el framework y su **ecosistema** se mantengan saludables y **sustentables**.
Al ✨ [**sponsorear FastAPI**](../help-fastapi.md#sponsor-the-author) ✨, estas compañías ayudan a asegurar que el framework y su **ecosistema** se mantengan saludables y **sustentables**.
Su sponsorship también demuestra un fuerte compromiso con la **comunidad** de FastAPI (tú), mostrando que no solo les importa ofrecer un **gran servicio**, sino también apoyar un **framework robusto y próspero**, FastAPI. 🙇
Por ejemplo, podrías querer probar:
* <a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
* <a href="https://www.stainless.com/?utm_source=fastapi&utm_medium=referral" class="external-link" target="_blank">Stainless</a>
* <a href="https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi" class="external-link" target="_blank">liblab</a>
* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)
* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)
* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)
Algunas de estas soluciones también pueden ser open source u ofrecer niveles gratuitos, así que puedes probarlas sin un compromiso financiero. Hay otros generadores de SDK comerciales disponibles y se pueden encontrar en línea. 🤓
@@ -66,7 +66,7 @@ npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
Esto generará un SDK de TypeScript en `./src/client`.
Puedes aprender cómo <a href="https://heyapi.dev/openapi-ts/get-started" class="external-link" target="_blank">instalar `@hey-api/openapi-ts`</a> y leer sobre el <a href="https://heyapi.dev/openapi-ts/output" class="external-link" target="_blank">output generado</a> en su sitio web.
Puedes aprender cómo [instalar `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started) y leer sobre el [output generado](https://heyapi.dev/openapi-ts/output) en su sitio web.
### Usar el SDK { #using-the-sdk }
+2 -2
View File
@@ -2,7 +2,7 @@
## Funcionalidades adicionales { #additional-features }
El [Tutorial - Guía del usuario](../tutorial/index.md){.internal-link target=_blank} principal debería ser suficiente para darte un recorrido por todas las funcionalidades principales de **FastAPI**.
El [Tutorial - Guía del usuario](../tutorial/index.md) principal debería ser suficiente para darte un recorrido por todas las funcionalidades principales de **FastAPI**.
En las siguientes secciones verás otras opciones, configuraciones y funcionalidades adicionales.
@@ -16,6 +16,6 @@ Y es posible que para tu caso de uso, la solución esté en una de ellas.
## Lee primero el Tutorial { #read-the-tutorial-first }
Aún podrías usar la mayoría de las funcionalidades en **FastAPI** con el conocimiento del [Tutorial - Guía del usuario](../tutorial/index.md){.internal-link target=_blank} principal.
Aún podrías usar la mayoría de las funcionalidades en **FastAPI** con el conocimiento del [Tutorial - Guía del usuario](../tutorial/index.md) principal.
Y las siguientes secciones asumen que ya lo leíste y que conoces esas ideas principales.
@@ -0,0 +1,63 @@
# JSON con Bytes como Base64 { #json-with-bytes-as-base64 }
Si tu app necesita recibir y enviar datos JSON, pero necesitas incluir datos binarios en él, puedes codificarlos como base64.
## Base64 vs Archivos { #base64-vs-files }
Considera primero si puedes usar [Archivos en request](../tutorial/request-files.md) para subir datos binarios y [Response personalizada - FileResponse](./custom-response.md#fileresponse--fileresponse-) para enviar datos binarios, en lugar de codificarlos en JSON.
JSON solo puede contener strings codificados en UTF-8, así que no puede contener bytes crudos.
Base64 puede codificar datos binarios en strings, pero para hacerlo necesita usar más caracteres que los datos binarios originales, así que normalmente sería menos eficiente que los archivos normales.
Usa base64 solo si definitivamente necesitas incluir datos binarios en JSON y no puedes usar archivos para eso.
## Pydantic `bytes` { #pydantic-bytes }
Puedes declarar un modelo de Pydantic con campos `bytes`, y luego usar `val_json_bytes` en la configuración del modelo para indicarle que use base64 para validar datos JSON de entrada; como parte de esa validación decodificará el string base64 en bytes.
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
Si revisas `/docs`, verás que el campo `data` espera bytes codificados en base64:
<div class="screenshot">
<img src="/img/tutorial/json-base64-bytes/image01.png">
</div>
Podrías enviar un request como:
```json
{
"description": "Some data",
"data": "aGVsbG8="
}
```
/// tip | Consejo
`aGVsbG8=` es la codificación base64 de `hello`.
///
Y luego Pydantic decodificará el string base64 y te dará los bytes originales en el campo `data` del modelo.
Recibirás una response como:
```json
{
"description": "Some data",
"content": "hello"
}
```
## Pydantic `bytes` para datos de salida { #pydantic-bytes-for-output-data }
También puedes usar campos `bytes` con `ser_json_bytes` en la configuración del modelo para datos de salida, y Pydantic serializará los bytes como base64 al generar la response JSON.
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
## Pydantic `bytes` para datos de entrada y salida { #pydantic-bytes-for-input-and-output-data }
Y por supuesto, puedes usar el mismo modelo configurado para usar base64 para manejar tanto la entrada (*validate*) con `val_json_bytes` como la salida (*serialize*) con `ser_json_bytes` al recibir y enviar datos JSON.
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
+5 -5
View File
@@ -1,8 +1,8 @@
# Middleware Avanzado { #advanced-middleware }
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.
@@ -91,7 +91,7 @@ Hay muchos otros middlewares ASGI.
Por ejemplo:
* <a href="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py" class="external-link" target="_blank">`ProxyHeadersMiddleware` de Uvicorn</a>
* <a href="https://github.com/florimondmanca/msgpack-asgi" class="external-link" target="_blank">MessagePack</a>
* [`ProxyHeadersMiddleware` de Uvicorn](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)
* [MessagePack](https://github.com/florimondmanca/msgpack-asgi)
Para ver otros middlewares disponibles, revisa <a href="https://www.starlette.dev/middleware/" class="external-link" target="_blank">la documentación de Middleware de Starlette</a> y la <a href="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).
+5 -5
View File
@@ -35,7 +35,7 @@ Esta parte es bastante normal, probablemente ya estés familiarizado con la mayo
/// tip | Consejo
El parámetro de query `callback_url` utiliza un tipo <a href="https://docs.pydantic.dev/latest/api/networks/" class="external-link" target="_blank">Url</a> de Pydantic.
El parámetro de query `callback_url` utiliza un tipo [Url](https://docs.pydantic.dev/latest/api/networks/) de Pydantic.
///
@@ -66,7 +66,7 @@ Este ejemplo no implementa el callback en sí (eso podría ser solo una línea d
El callback real es solo un request HTTP.
Cuando implementes el callback tú mismo, podrías usar algo como <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> o <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a>.
Cuando implementes el callback tú mismo, podrías usar algo como [HTTPX](https://www.python-httpx.org) o [Requests](https://requests.readthedocs.io/).
///
@@ -106,11 +106,11 @@ Debería verse como una *path operation* normal de FastAPI:
Hay 2 diferencias principales respecto a una *path operation* normal:
* No necesita tener ningún código real, porque tu aplicación nunca llamará a este código. Solo se usa para documentar la *API externa*. Así que, la función podría simplemente tener `pass`.
* El *path* puede contener una <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">expresión OpenAPI 3</a> (ver más abajo) donde puede usar variables con parámetros y partes del request original enviado a *tu API*.
* El *path* puede contener una [expresión OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (ver más abajo) donde puede usar variables con parámetros y partes del request original enviado a *tu API*.
### La expresión del path del callback { #the-callback-path-expression }
El *path* del callback puede tener una <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">expresión OpenAPI 3</a> que puede contener partes del request original enviado a *tu API*.
El *path* del callback puede tener una [expresión OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) que puede contener partes del request original enviado a *tu API*.
En este caso, es el `str`:
@@ -179,7 +179,7 @@ Observa que no estás pasando el router en sí (`invoices_callback_router`) a `c
### Revisa la documentación { #check-the-docs }
Ahora puedes iniciar tu aplicación e ir a <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Ahora puedes iniciar tu aplicación e ir a [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
Verás tu documentación incluyendo una sección de "Callbacks" para tu *path operation* que muestra cómo debería verse la *API externa*:
+1 -1
View File
@@ -48,7 +48,7 @@ Esto es porque se espera que **tus usuarios** definan el actual **URL path** don
### Revisa la documentación { #check-the-docs }
Ahora puedes iniciar tu app e ir a <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Ahora puedes iniciar tu app e ir a [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
Verás que tu documentación tiene las *path operations* normales y ahora también algunos **webhooks**:
@@ -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.
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 }
@@ -68,7 +68,7 @@ Cuando declaras una *path operation* en tu aplicación, **FastAPI** genera autom
/// note | Detalles técnicos
En la especificación de OpenAPI se llama el <a href="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.
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`:
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el request body ni siquiera es <dfn title="convertido desde algún formato plano, como bytes, a objetos de Python">parseado</dfn> como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de parsearlo de alguna manera.
En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el request body ni siquiera es <dfn title="convertido desde algún formato plano, como bytes, a objetos de Python">parseado</dfn> como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de hacer parse de él de alguna manera.
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.
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:
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
@@ -1,6 +1,6 @@
# Response - Cambiar Código de Estado { #response-change-status-code }
Probablemente leíste antes que puedes establecer un [Código de Estado de Response](../tutorial/response-status-code.md){.internal-link target=_blank} por defecto.
Probablemente leíste antes que puedes establecer un [Código de Estado de Response](../tutorial/response-status-code.md) por defecto.
Pero en algunos casos necesitas devolver un código de estado diferente al predeterminado.
+2 -2
View File
@@ -20,7 +20,7 @@ También puedes declarar el parámetro `Response` en las dependencias, y estable
También puedes crear cookies al devolver una `Response` directamente en tu código.
Para hacer eso, puedes crear un response como se describe en [Devolver un Response Directamente](response-directly.md){.internal-link target=_blank}.
Para hacer eso, puedes crear un response como se describe en [Devolver un Response Directamente](response-directly.md).
Luego establece Cookies en ella, y luego devuélvela:
@@ -48,4 +48,4 @@ Y como el `Response` se puede usar frecuentemente para establecer headers y cook
///
Para ver todos los parámetros y opciones disponibles, revisa la <a href="https://www.starlette.dev/responses/#set-cookie" class="external-link" target="_blank">documentación en Starlette</a>.
Para ver todos los parámetros y opciones disponibles, revisa la [documentación en Starlette](https://www.starlette.dev/responses/#set-cookie).
+25 -7
View File
@@ -2,19 +2,23 @@
Cuando creas una *path operation* en **FastAPI**, normalmente puedes devolver cualquier dato desde ella: un `dict`, una `list`, un modelo de Pydantic, un modelo de base de datos, etc.
Por defecto, **FastAPI** convertiría automáticamente ese valor de retorno a JSON usando el `jsonable_encoder` explicado en [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
Si declaras un [Response Model](../tutorial/response-model.md) FastAPI lo usará para serializar los datos a JSON, usando Pydantic.
Luego, detrás de escena, pondría esos datos compatibles con JSON (por ejemplo, un `dict`) dentro de un `JSONResponse` que se usaría para enviar el response al cliente.
Si no declaras un response model, FastAPI usará el `jsonable_encoder` explicado en [JSON Compatible Encoder](../tutorial/encoder.md) y lo pondrá en un `JSONResponse`.
Pero puedes devolver un `JSONResponse` directamente desde tus *path operations*.
También podrías crear un `JSONResponse` directamente y devolverlo.
Esto podría ser útil, por ejemplo, para devolver headers o cookies personalizados.
/// tip | Consejo
Normalmente tendrás mucho mejor rendimiento usando un [Response Model](../tutorial/response-model.md) que devolviendo un `JSONResponse` directamente, ya que de esa forma serializa los datos usando Pydantic, en Rust.
///
## Devolver una `Response` { #return-a-response }
De hecho, puedes devolver cualquier `Response` o cualquier subclase de ella.
/// tip | Consejo
/// info | Información
`JSONResponse` en sí misma es una subclase de `Response`.
@@ -26,6 +30,8 @@ No hará ninguna conversión de datos con los modelos de Pydantic, no convertir
Esto te da mucha flexibilidad. Puedes devolver cualquier tipo de datos, sobrescribir cualquier declaración o validación de datos, etc.
También te da mucha responsabilidad. Tienes que asegurarte de que los datos que devuelves sean correctos, en el formato correcto, que se puedan serializar, etc.
## Usar el `jsonable_encoder` en una `Response` { #using-the-jsonable-encoder-in-a-response }
Como **FastAPI** no realiza cambios en una `Response` que devuelves, tienes que asegurarte de que sus contenidos estén listos para ello.
@@ -50,16 +56,28 @@ El ejemplo anterior muestra todas las partes que necesitas, pero aún no es muy
Ahora, veamos cómo podrías usar eso para devolver un response personalizado.
Digamos que quieres devolver un response en <a href="https://en.wikipedia.org/wiki/XML" class="external-link" target="_blank">XML</a>.
Digamos que quieres devolver un response en [XML](https://en.wikipedia.org/wiki/XML).
Podrías poner tu contenido XML en un string, poner eso en un `Response`, y devolverlo:
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
## Cómo funciona un Response Model { #how-a-response-model-works }
Cuando declaras un [Response Model - Return Type](../tutorial/response-model.md) en una *path operation*, **FastAPI** lo usará para serializar los datos a JSON, usando Pydantic.
{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
Como eso sucederá del lado de Rust, el rendimiento será mucho mejor que si se hiciera con Python normal y la clase `JSONResponse`.
Al usar un `response_model` o tipo de retorno, FastAPI no usará el `jsonable_encoder` para convertir los datos (lo cual sería más lento) ni la clase `JSONResponse`.
En su lugar, toma los bytes JSON generados con Pydantic usando el response model (o tipo de retorno) y devuelve una `Response` con el media type correcto para JSON directamente (`application/json`).
## Notas { #notes }
Cuando devuelves una `Response` directamente, sus datos no son validados, convertidos (serializados), ni documentados automáticamente.
Pero aún puedes documentarlo como se describe en [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.
Pero aún puedes documentarlo como se describe en [Additional Responses in OpenAPI](additional-responses.md).
Puedes ver en secciones posteriores cómo usar/declarar estas `Response`s personalizadas mientras todavía tienes conversión automática de datos, documentación, etc.
+3 -3
View File
@@ -20,7 +20,7 @@ También puedes declarar el parámetro `Response` en dependencias y establecer h
También puedes agregar headers cuando devuelves un `Response` directamente.
Crea un response como se describe en [Retorna un Response Directamente](response-directly.md){.internal-link target=_blank} y pasa los headers como un parámetro adicional:
Crea un response como se describe en [Retorna un Response Directamente](response-directly.md) y pasa los headers como un parámetro adicional:
{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
@@ -36,6 +36,6 @@ Y como el `Response` se puede usar frecuentemente para establecer headers y cook
## Headers Personalizados { #custom-headers }
Ten en cuenta que los headers propietarios personalizados se pueden agregar <a href="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 headers propietarios personalizados se pueden agregar [usando el prefijo `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).
Pero si tienes headers personalizados que quieres que un cliente en un navegador pueda ver, necesitas agregarlos a tus configuraciones de CORS (leer más en [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), usando el parámetro `expose_headers` documentado en <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">la documentación CORS de Starlette</a>.
Pero si tienes headers personalizados que quieres que un cliente en un navegador pueda ver, necesitas agregarlos a tus configuraciones de CORS (leer más en [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), usando el parámetro `expose_headers` documentado en [la documentación CORS de Starlette](https://www.starlette.dev/middleware/#corsmiddleware).
@@ -32,7 +32,7 @@ Aquí hay un ejemplo más completo.
Usa una dependencia para comprobar si el nombre de usuario y la contraseña son correctos.
Para esto, usa el módulo estándar de Python <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a> para verificar el nombre de usuario y la contraseña.
Para esto, usa el módulo estándar de Python [`secrets`](https://docs.python.org/3/library/secrets.html) para verificar el nombre de usuario y la contraseña.
`secrets.compare_digest()` necesita tomar `bytes` o un `str` que solo contenga caracteres ASCII (los carácteres en inglés), esto significa que no funcionaría con caracteres como `á`, como en `Sebastián`.
+3 -3
View File
@@ -2,11 +2,11 @@
## Funcionalidades Adicionales { #additional-features }
Hay algunas funcionalidades extra para manejar la seguridad aparte de las cubiertas en el [Tutorial - Guía del Usuario: Seguridad](../../tutorial/security/index.md){.internal-link target=_blank}.
Hay algunas funcionalidades extra para manejar la seguridad aparte de las cubiertas en el [Tutorial - Guía del Usuario: Seguridad](../../tutorial/security/index.md).
/// tip | Consejo
Las siguientes secciones **no son necesariamente "avanzadas"**.
Las siguientes secciones no son necesariamente "avanzadas".
Y es posible que para tu caso de uso, la solución esté en una de ellas.
@@ -14,6 +14,6 @@ Y es posible que para tu caso de uso, la solución esté en una de ellas.
## Lee primero el Tutorial { #read-the-tutorial-first }
Las siguientes secciones asumen que ya leíste el [Tutorial - Guía del Usuario: Seguridad](../../tutorial/security/index.md){.internal-link target=_blank} principal.
Las siguientes secciones asumen que ya leíste el [Tutorial - Guía del Usuario: Seguridad](../../tutorial/security/index.md) principal.
Todas están basadas en los mismos conceptos, pero permiten algunas funcionalidades adicionales.
@@ -60,7 +60,7 @@ Para OAuth2 son solo strings.
## Vista global { #global-view }
Primero, echemos un vistazo rápido a las partes que cambian desde los ejemplos en el **Tutorial - User Guide** principal para [OAuth2 con Password (y hashing), Bearer con tokens JWT](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Ahora usando scopes de OAuth2:
Primero, echemos un vistazo rápido a las partes que cambian desde los ejemplos en el **Tutorial - User Guide** principal para [OAuth2 con Password (y hashing), Bearer con tokens JWT](../../tutorial/security/oauth2-jwt.md). Ahora usando scopes de OAuth2:
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}
@@ -271,4 +271,4 @@ Pero al final, están implementando el mismo estándar OAuth2.
## `Security` en `dependencies` del decorador { #security-in-decorator-dependencies }
De la misma manera que puedes definir una `list` de `Depends` en el parámetro `dependencies` del decorador (como se explica en [Dependencias en decoradores de path operation](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), también podrías usar `Security` con `scopes` allí.
De la misma manera que puedes definir una `list` de `Depends` en el parámetro `dependencies` del decorador (como se explica en [Dependencias en decoradores de path operation](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)), también podrías usar `Security` con `scopes` allí.
+8 -8
View File
@@ -8,7 +8,7 @@ Por esta razón, es común proporcionarlas en variables de entorno que son leíd
/// 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 }
Afortunadamente, Pydantic proporciona una gran utilidad para manejar estas configuraciones provenientes de variables de entorno con <a href="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/).
### Instalar `pydantic-settings` { #install-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`:
<div class="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 }
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:
@@ -112,7 +112,7 @@ Y luego usarlo en un archivo `main.py`:
/// 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 <a href="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
@@ -197,7 +197,7 @@ Y luego actualizar tu `config.py` con:
/// tip | Consejo
El atributo `model_config` se usa solo para configuración de Pydantic. Puedes leer más en <a href="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.
`@lru_cache` es parte de `functools`, que es parte del paquete estándar de Python, puedes leer más sobre él en las <a href="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).
## Resumen { #recap }
+117
View File
@@ -0,0 +1,117 @@
# Transmitir datos { #stream-data }
Si quieres transmitir datos que se puedan estructurar como JSON, deberías [Transmitir JSON Lines](../tutorial/stream-json-lines.md).
Pero si quieres transmitir datos binarios puros o strings, aquí tienes cómo hacerlo.
/// info | Información
Añadido en FastAPI 0.134.0.
///
## Casos de uso { #use-cases }
Podrías usar esto si quieres transmitir strings puros, por ejemplo directamente de la salida de un servicio de AI LLM.
También podrías usarlo para transmitir archivos binarios grandes, donde transmites cada bloque de datos a medida que lo lees, sin tener que leerlo todo en memoria de una sola vez.
También podrías transmitir video o audio de esta manera; incluso podría generarse mientras lo procesas y lo envías.
## Un `StreamingResponse` con `yield` { #a-streamingresponse-with-yield }
Si declaras un `response_class=StreamingResponse` en tu *path operation function*, puedes usar `yield` para enviar cada bloque de datos a su vez.
{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}
FastAPI entregará cada bloque de datos a `StreamingResponse` tal cual, no intentará convertirlo a JSON ni nada parecido.
### *path operation functions* no async { #non-async-path-operation-functions }
También puedes usar funciones `def` normales (sin `async`) y usar `yield` de la misma manera.
{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}
### Sin anotación { #no-annotation }
Realmente no necesitas declarar la anotación de tipo de retorno para transmitir datos binarios.
Como FastAPI no intentará convertir los datos a JSON con Pydantic ni serializarlos de ninguna manera, en este caso la anotación de tipos es solo para que la use tu editor y tus herramientas; FastAPI no la usará.
{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}
Esto también significa que con `StreamingResponse` tienes la libertad y la responsabilidad de producir y codificar los bytes de datos exactamente como necesites enviarlos, independientemente de las anotaciones de tipos. 🤓
### Transmitir bytes { #stream-bytes }
Uno de los casos de uso principales sería transmitir `bytes` en lugar de strings; por supuesto puedes hacerlo.
{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}
## Un `PNGStreamingResponse` personalizado { #a-custom-pngstreamingresponse }
En los ejemplos anteriores, se transmitieron los bytes de datos, pero la response no tenía un header `Content-Type`, así que el cliente no sabía qué tipo de datos estaba recibiendo.
Puedes crear una subclase personalizada de `StreamingResponse` que establezca el header `Content-Type` al tipo de datos que estás transmitiendo.
Por ejemplo, puedes crear un `PNGStreamingResponse` que establezca el header `Content-Type` a `image/png` usando el atributo `media_type`:
{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}
Luego puedes usar esta nueva clase en `response_class=PNGStreamingResponse` en tu *path operation function*:
{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}
### Simular un archivo { #simulate-a-file }
En este ejemplo estamos simulando un archivo con `io.BytesIO`, que es un objeto tipo archivo que vive solo en memoria, pero nos permite usar la misma interfaz.
Por ejemplo, podemos iterarlo para consumir su contenido, como podríamos con un archivo.
{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}
/// note | Detalles técnicos
Las otras dos variables, `image_base64` y `binary_image`, son una imagen codificada en Base64 y luego convertida a bytes, para después pasarla a `io.BytesIO`.
Solo para que pueda vivir en el mismo archivo para este ejemplo y puedas copiarlo y ejecutarlo tal cual. 🥚
///
Al usar un bloque `with`, nos aseguramos de que el objeto tipo archivo se cierre cuando termine la función generadora (la función con `yield`). Es decir, después de que termine de enviar la response.
No sería tan importante en este ejemplo específico porque es un archivo falso en memoria (con `io.BytesIO`), pero con un archivo real sí sería importante asegurarse de que el archivo se cierre al terminar de trabajar con él.
### Archivos y async { #files-and-async }
En la mayoría de los casos, los objetos tipo archivo no son compatibles con `async` y `await` por defecto.
Por ejemplo, no tienen un `await file.read()`, ni un `async for chunk in file`.
Y en muchos casos leerlos sería una operación bloqueante (que podría bloquear el event loop), porque se leen desde disco o desde la red.
/// info | Información
El ejemplo anterior es en realidad una excepción, porque el objeto `io.BytesIO` ya está en memoria, así que leerlo no bloqueará nada.
Pero en muchos casos leer un archivo u objeto tipo archivo sí bloquearía.
///
Para evitar bloquear el event loop, puedes simplemente declarar la *path operation function* con un `def` normal en lugar de `async def`; de esa forma FastAPI la ejecutará en un worker de threadpool para evitar bloquear el loop principal.
{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}
/// tip | Consejo
Si necesitas llamar código bloqueante desde dentro de una función async, o una función async desde dentro de una función bloqueante, podrías usar [Asyncer](https://asyncer.tiangolo.com), un paquete hermano de FastAPI.
///
### `yield from` { #yield-from }
Cuando estés iterando sobre algo, como un objeto tipo archivo, y estés haciendo `yield` para cada elemento, también podrías usar `yield from` para hacer `yield` de cada elemento directamente y saltarte el `for`.
Esto no es particular de FastAPI, es simplemente Python, pero es un truco útil que conviene conocer. 😎
{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}
@@ -0,0 +1,88 @@
# Chequeo estricto de Content-Type { #strict-content-type-checking }
Por defecto, **FastAPI** usa un chequeo estricto del header `Content-Type` para request bodies JSON, esto significa que las requests JSON deben incluir un header `Content-Type` válido (p. ej. `application/json`) para que el request body se parse como JSON.
## Riesgo de CSRF { #csrf-risk }
Este comportamiento por defecto provee protección contra una clase de ataques de **Cross-Site Request Forgery (CSRF)** en un escenario muy específico.
Estos ataques aprovechan que los navegadores permiten que los scripts envíen requests sin hacer un preflight de CORS cuando:
* no tienen un header `Content-Type` (p. ej. usando `fetch()` con un body `Blob`)
* y no envían credenciales de autenticación.
Este tipo de ataque es relevante principalmente cuando:
* la aplicación corre localmente (p. ej. en `localhost`) o en una red interna
* y la aplicación no tiene ninguna autenticación, espera que cualquier request de la misma red sea confiable.
## Ejemplo de ataque { #example-attack }
Imagina que construyes una forma de ejecutar un agente de IA local.
Provee un API en
```
http://localhost:8000/v1/agents/multivac
```
También hay un frontend en
```
http://localhost:8000
```
/// tip | Consejo
Ten en cuenta que ambos tienen el mismo host.
///
Luego, usando el frontend, puedes hacer que el agente de IA haga cosas en tu nombre.
Como está corriendo localmente y no en Internet abierta, decides no tener ninguna autenticación configurada, confiando simplemente en el acceso a la red local.
Entonces, uno de tus usuarios podría instalarlo y ejecutarlo localmente.
Después podría abrir un sitio web malicioso, por ejemplo algo como
```
https://evilhackers.example.com
```
Y ese sitio malicioso envía requests usando `fetch()` con un body `Blob` al API local en
```
http://localhost:8000/v1/agents/multivac
```
Aunque el host del sitio malicioso y el de la app local sea diferente, el navegador no disparará un preflight de CORS porque:
* Está corriendo sin ninguna autenticación, no tiene que enviar credenciales.
* El navegador cree que no está enviando JSON (por la falta del header `Content-Type`).
Entonces el sitio malicioso podría hacer que el agente de IA local envíe mensajes agresivos al exjefe del usuario... o peor. 😅
## Internet abierta { #open-internet }
Si tu app está en Internet abierta, no “confiarías en la red” ni permitirías que cualquiera envíe requests privilegiadas sin autenticación.
Los atacantes podrían simplemente ejecutar un script para enviar requests a tu API, sin necesidad de interacción del navegador, así que probablemente ya estás asegurando cualquier endpoint privilegiado.
En ese caso, este ataque/riesgo no aplica a ti.
Este riesgo y ataque es relevante principalmente cuando la app corre en la red local y esa es la única protección asumida.
## Permitir requests sin Content-Type { #allowing-requests-without-content-type }
Si necesitas soportar clientes que no envían un header `Content-Type`, puedes desactivar el chequeo estricto configurando `strict_content_type=False`:
{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}
Con esta configuración, las requests sin un header `Content-Type` tendrán su body parseado como JSON, que es el mismo comportamiento de versiones anteriores de FastAPI.
/// info | Información
Este comportamiento y configuración se añadieron en FastAPI 0.132.0.
///
+5 -5
View File
@@ -30,25 +30,25 @@ En este caso, se montará en el path `/subapi`:
### Revisa la documentación automática de la API { #check-the-automatic-api-docs }
Ahora, ejecuta el comando `fastapi` con tu archivo:
Ahora, ejecuta el comando `fastapi`:
<div class="termy">
```console
$ fastapi dev main.py
$ fastapi dev
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Y abre la documentación en <a href="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 para la aplicación principal, incluyendo solo sus propias _path operations_:
<img src="/img/tutorial/sub-applications/image01.png">
Y luego, abre la documentación para la sub-aplicación, en <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>.
Y luego, abre la documentación para la sub-aplicación, en [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs).
Verás la documentación automática de la API para la sub-aplicación, incluyendo solo sus propias _path operations_, todas bajo el prefijo correcto del sub-path `/subapi`:
@@ -64,4 +64,4 @@ De esa manera, la sub-aplicación sabrá usar ese prefijo de path para la interf
Y la sub-aplicación también podría tener sus propias sub-aplicaciones montadas y todo funcionaría correctamente, porque FastAPI maneja todos estos `root_path`s automáticamente.
Aprenderás más sobre el `root_path` y cómo usarlo explícitamente en la sección sobre [Detrás de un Proxy](behind-a-proxy.md){.internal-link target=_blank}.
Aprenderás más sobre el `root_path` y cómo usarlo explícitamente en la sección sobre [Detrás de un Proxy](behind-a-proxy.md).
+2 -2
View File
@@ -8,7 +8,7 @@ Hay utilidades para configurarlo fácilmente que puedes usar directamente en tu
## 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`:
<div class="termy">
@@ -123,4 +123,4 @@ Y porque estás usando `StaticFiles`, ese archivo CSS sería servido automática
## Más detalles { #more-details }
Para más detalles, incluyendo cómo testear plantillas, revisa <a href="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/).
+1 -1
View File
@@ -8,6 +8,6 @@ Para esto, usas el `TestClient` en un statement `with`, conectándote al WebSock
/// note | Nota
Para más detalles, revisa la documentación de Starlette sobre <a href="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).
///
@@ -15,7 +15,7 @@ Pero hay situaciones donde podrías necesitar acceder al objeto `Request` direct
## Detalles sobre el objeto `Request` { #details-about-the-request-object }
Como **FastAPI** es en realidad **Starlette** por debajo, con una capa de varias herramientas encima, puedes usar el objeto <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">`Request`</a> de Starlette directamente cuando lo necesites.
Como **FastAPI** es en realidad **Starlette** por debajo, con una capa de varias herramientas encima, puedes usar el objeto de Starlette [`Request`](https://www.starlette.dev/requests/) directamente cuando lo necesites.
También significa que si obtienes datos del objeto `Request` directamente (por ejemplo, leyendo el cuerpo) no serán validados, convertidos o documentados (con OpenAPI, para la interfaz automática de usuario de la API) por FastAPI.
@@ -45,7 +45,7 @@ De la misma manera, puedes declarar cualquier otro parámetro como normalmente,
## Documentación de `Request` { #request-documentation }
Puedes leer más detalles sobre el <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">objeto `Request` en el sitio de documentación oficial de Starlette</a>.
Puedes leer más detalles sobre el [objeto `Request` en el sitio de documentación oficial de Starlette](https://www.starlette.dev/requests/).
/// note | Detalles Técnicos
+12 -12
View File
@@ -1,10 +1,10 @@
# WebSockets { #websockets }
Puedes usar <a href="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 }
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"):
<div class="termy">
@@ -64,19 +64,19 @@ Puedes recibir y enviar datos binarios, de texto y JSON.
## 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:
<div class="termy">
```console
$ fastapi dev main.py
$ fastapi dev
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Abre tu navegador en <a href="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:
@@ -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`.
Puedes usar un código de cierre de los <a href="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 }
Si tu archivo se llama `main.py`, ejecuta tu aplicación con:
Ejecuta tu aplicación:
<div class="termy">
```console
$ fastapi dev main.py
$ fastapi dev
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Abre tu navegador en <a href="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:
@@ -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.
Si necesitas algo fácil de integrar con FastAPI pero que sea más robusto, soportado por Redis, PostgreSQL u otros, revisa <a href="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:
* <a href="https://www.starlette.dev/websockets/" class="external-link" target="_blank">La clase `WebSocket`</a>.
* <a href="https://www.starlette.dev/endpoints/#websocketendpoint" class="external-link" target="_blank">Manejo de WebSocket basado en clases</a>.
* [La clase `WebSocket`](https://www.starlette.dev/websockets/).
* [Manejo de WebSocket basado en clases](https://www.starlette.dev/endpoints/#websocketendpoint).
+3 -3
View File
@@ -1,6 +1,6 @@
# 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.
@@ -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**.
Si lo ejecutas y vas a <a href="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
Hello, World from Flask!
```
Y si vas a <a href="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:
```JSON
{