Por defecto, **FastAPI** devolverá las respuestas utilizando una `JSONResponse`, poniendo el contenido que devuelves en tu *operación de path* dentro de esa`JSONResponse`.
Por defecto, **FastAPI** devolverá los responses usando un `JSONResponse`, colocando el contenido que devuelves desde tu *path operation* dentro de ese`JSONResponse`.
Utilizará el código de estado por defecto, o el que hayas asignado en tu *operación de path*.
Usará el código de estado por defecto o el que configures en tu *path operation*.
## Códigos de estado adicionales
Si quieres devolver códigos de estado adicionales además del principal, puedes hacerlo devolviendo directamente una `Response`, como una `JSONResponse`, y asignar directamente el código de estado adicional.
Si quieres devolver códigos de estado adicionales aparte del principal, puedes hacerlo devolviendo un `Response` directamente, como un `JSONResponse`, y configurando el código de estado adicional directamente.
Por ejemplo, digamos que quieres tener una *operación de path* que permita actualizar ítems y devolver códigos de estado HTTP 200 "OK" cuando sea exitosa.
Por ejemplo, supongamos que quieres tener una *path operation* que permita actualizar elementos, y devuelva códigos de estado HTTP de 200 "OK" cuando sea exitoso.
Pero también quieres que acepte nuevos ítems. Cuando los ítems no existan anteriormente, serán creados y devolverá un código de estado HTTP 201 "Created".
Pero también quieres que acepte nuevos elementos. Y cuando los elementos no existían antes, los crea y devuelve un código de estado HTTP de 201 "Created".
Para conseguir esto importa `JSONResponse` y devuelve ahí directamente tu contenido, asignando el `status_code` que quieras:
Para lograr eso, importa `JSONResponse`, y devuelve tu contenido allí directamente, configurando el `status_code` que deseas:
Cuando devuelves directamente una `Response`, como en los ejemplos anteriores, será devuelta directamente.
Cuando devuelves un `Response` directamente, como en el ejemplo anterior, se devuelve directamente.
No será serializado con el modelo, etc.
No se serializará con un modelo, etc.
Asegúrate de que la respuesta tenga los datos que quieras, y que los valores sean JSON válidos (si estás usando `JSONResponse`).
Asegúrate de que tenga los datos que deseas que tenga y que los valores sean JSON válidos (si estás usando `JSONResponse`).
///
/// note | Detalles Técnicos
También podrías utilizar `from starlette.responses import JSONResponse`.
También podrías usar `from starlette.responses import JSONResponse`.
**FastAPI** provee las mismas `starlette.responses` que `fastapi.responses` simplemente como una convención para ti, el desarrollador. Pero la mayoría de las respuestas disponibles vienen directamente de Starlette. Lo mismo con `status`.
**FastAPI** proporciona los mismos `starlette.responses` que `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles provienen directamente de Starlette. Lo mismo con `status`.
///
## OpenAPI y documentación de API
Si quieres devolver códigos de estado y respuestas adicionales directamente, estas no estarán incluidas en el schema de OpenAPI (documentación de API), porque FastAPI no tiene una manera de conocer de antemano lo que vas a devolver.
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 documentar eso en tu código usando [Respuestas Adicionales](additional-responses.md){.internal-link target=_blank}.
Pero puedes documentarlo en tu código, usando: [Responses Adicionales](additional-responses.md){.internal-link target=_blank}.
El [Tutorial - Guía de Usuario](../tutorial/index.md){.internal-link target=_blank} principal debe ser suficiente para darte un paseo por todas las características principales de **FastAPI**
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**.
En las secciones siguientes verás otras opciones, configuraciones, y características adicionales.
En las siguientes secciones verás otras opciones, configuraciones y funcionalidades adicionales.
/// tip | Consejo
Las próximas secciones **no son necesariamente "avanzadas"**.
Las siguientes secciones **no son necesariamente "avanzadas"**.
Y es posible que para tu caso, la solución se encuentre en una de estas.
Y es posible que para tu caso de uso, la solución esté en una de ellas.
///
## Lee primero el Tutorial
Puedes continuar usando la mayoría de las características de **FastAPI** con el conocimiento del [Tutorial - Guía de 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){.internal-link target=_blank} principal.
En las siguientes secciones se asume que lo has leído y conoces esas ideas principales.
Y las siguientes secciones asumen que ya lo leíste y que conoces esas ideas principales.
## Cursos externos
Aunque el [Tutorial - Guía del usuario](../tutorial/index.md){.internal-link target=_blank} y esta **Guía avanzada del usuario** están escritos como un tutorial guiado (como un libro) y deberían ser suficientes para que **aprendas FastAPI**, podrías querer complementarlo con cursos adicionales.
O podría ser que simplemente prefieras tomar otros cursos porque se adaptan mejor a tu estilo de aprendizaje.
Algunos proveedores de cursos ✨ [**sponsorean FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, esto asegura el desarrollo continuo y saludable de FastAPI y su **ecosistema**.
Y muestra su verdadero compromiso con FastAPI y su **comunidad** (tú), ya que no solo quieren brindarte una **buena experiencia de aprendizaje** sino que también quieren asegurarse de que tengas un **buen y saludable framework**, FastAPI. 🙇
### Usando el nombre de la *función de la operación de path* en el operationId
### Usar el nombre de la *función de path operation* como el operationId
Si quieres usar tus nombres de funciones de API como `operationId`s, puedes iterar sobre todos ellos y sobrescribir `operation_id` de cada *operación de path* usando su `APIRoute.name`.
Si quieres usar los nombres de las funciones de tus APIs como `operationId`s, puedes iterar sobre todas ellas y sobrescribir el `operation_id` de cada *path operation* usando su `APIRoute.name`.
Deberías hacerlo después de adicionar todas tus *operaciones de path*.
Deberías hacerlo después de agregar todas tus *path operations*.
Si llamas manualmente a `app.openapi()`, debes actualizar el `operationId`s antes de hacerlo.
Si llamas manualmente a `app.openapi()`, deberías actualizar los `operationId`s antes de eso.
///
/// warning | Advertencia
Si haces esto, debes asegurarte de que cada una de tus *funciones de las operaciones de path* tenga un nombre único.
Si haces esto, tienes que asegurarte de que cada una de tus *funciones de path operation* tenga un nombre único.
Incluso si están en diferentes módulos (archivos Python).
Incluso si están en diferentes módulos (archivos de Python).
///
## Excluir de OpenAPI
Para excluir una *operación de path* del esquema OpenAPI generado (y por tanto del la documentación generada automáticamente), usa el parámetro `include_in_schema` y asigna el valor como `False`;
Para excluir una *path operation* del esquema OpenAPI generado (y por lo tanto, de los sistemas de documentación automática), utiliza el parámetro `include_in_schema` y configúralo en `False`:
Probablemente has visto cómo declarar el `response_model` y el `status_code` para una *path operation*.
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}.
## OpenAPI Extra
Cuando declaras una *path operation* en tu aplicación, **FastAPI** genera automáticamente los metadatos relevantes sobre esa *path operation* para incluirlos en el esquema de OpenAPI.
/// note | Nota
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>.
///
Tiene toda la información sobre la *path operation* y se usa para generar la documentación automática.
Incluye los `tags`, `parameters`, `requestBody`, `responses`, etc.
Este esquema de OpenAPI específico de *path operation* normalmente se genera automáticamente por **FastAPI**, pero también puedes extenderlo.
/// tip | Consejo
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}.
///
Puedes extender el esquema de OpenAPI para una *path operation* usando el parámetro `openapi_extra`.
### Extensiones de OpenAPI
Este `openapi_extra` puede ser útil, por ejemplo, para declarar [Extensiones de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
Y si ves el OpenAPI resultante (en `/openapi.json` en tu API), verás tu extensión como parte de la *path operation* específica también:
```JSON hl_lines="22"
{
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
},
"paths": {
"/items/": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"x-aperture-labs-portal": "blue"
}
}
}
}
```
### Esquema de *path operation* personalizada de OpenAPI
El diccionario en `openapi_extra` se combinará profundamente con el esquema de OpenAPI generado automáticamente para la *path operation*.
Por lo tanto, podrías añadir datos adicionales al esquema generado automáticamente.
Por ejemplo, podrías decidir leer y validar el request con tu propio código, sin usar las funcionalidades automáticas de FastAPI con Pydantic, pero aún podrías querer definir el request en el esquema de OpenAPI.
En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el cuerpo del request ni siquiera se <abbrtitle="converted from some plain format, like bytes, into Python objects">parse</abbr> como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de parsearlo de alguna manera.
Sin embargo, podemos declarar el esquema esperado para el cuerpo del request.
### Tipo de contenido personalizado de OpenAPI
Usando este mismo truco, podrías usar un modelo Pydantic para definir el esquema JSON que luego se incluye en la sección personalizada del esquema OpenAPI para la *path operation*.
Y podrías hacer esto incluso si el tipo de datos en el request no es JSON.
Por ejemplo, en esta aplicación no usamos la funcionalidad integrada de FastAPI para extraer el esquema JSON de los modelos Pydantic ni la validación automática para JSON. De hecho, estamos declarando el tipo de contenido del request como YAML, no JSON:
En la versión 1 de Pydantic el método para obtener el esquema JSON para un modelo se llamaba `Item.schema()`, en la versión 2 de Pydantic, el método se llama `Item.model_json_schema()`.
///
Sin embargo, aunque no estamos usando la funcionalidad integrada por defecto, aún estamos usando un modelo Pydantic para generar manualmente el esquema JSON 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.
Y luego en nuestro código, parseamos ese contenido YAML directamente, y nuevamente estamos usando el mismo modelo Pydantic para validar el contenido YAML:
En la versión 1 de Pydantic el método para parsear y validar un objeto era `Item.parse_obj()`, en la versión 2 de Pydantic, el método se llama `Item.model_validate()`.
///
/// tip | Consejo
Aquí reutilizamos el mismo modelo Pydantic.
Pero de la misma manera, podríamos haberlo validado de alguna otra forma.
Probablemente ya has leído con anterioridad que puedes establecer un [Response Status Code](../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){.internal-link target=_blank} por defecto.
Pero en algunos casos necesitas retornar un status code diferente al predeterminado.
Pero en algunos casos necesitas devolver un código de estado diferente al predeterminado.
## Casos de uso
## Caso de uso
Por ejemplo, imagina que quieres retornar un HTTP status code de "OK" `200` por defecto.
Por ejemplo, imagina que quieres devolver un código de estado HTTP de "OK" `200` por defecto.
Pero si los datos no existen, quieres crearlos y retornar un HTTP status code de "CREATED" `201`.
Pero si los datos no existieran, quieres crearlos y devolver un código de estado HTTP de "CREATED" `201`.
Pero aún quieres poder filtrar y convertir los datos que retornas con un `response_model`.
Pero todavía quieres poder filtrar y convertir los datos que devuelves con un `response_model`.
Para esos casos, puedes usar un parámetro `Response`.
## Usar un parámetro `Response`
## Usa un parámetro `Response`
Puedes declarar un parámetro de tipo `Response` en tu *función de la operación de path* (como puedes hacer para cookies y headers).
Puedes declarar un parámetro de tipo `Response` en tu *función de path operation* (como puedes hacer para cookies y headers).
Y luego puedes establecer el `status_code` en ese objeto de respuesta*temporal*.
Y luego puedes establecer el `status_code` en ese objeto de response*temporal*.
Y luego puedes retornar cualquier objeto que necesites, como normalmente lo harías (un `dict`, un modelo de base de datos, etc).
Y luego puedes devolver cualquier objeto que necesites, como lo harías normalmente (un `dict`, un modelo de base de datos, etc.).
Y si declaraste un `response_model`, aún se usará para filtrar y convertir el objeto que retornaste.
Y si declaraste un `response_model`, todavía se utilizará para filtrar y convertir el objeto que devolviste.
**FastAPI** usará esa respuesta*temporal* para extraer el código de estado (también cookies y headers), y los pondrá en la respuesta final que contiene el valor que retornaste, filtrado por cualquier `response_model`.
**FastAPI** usará ese response*temporal* para extraer el código de estado (también cookies y headers), y los pondrá en el response final que contiene el valor que devolviste, filtrado por cualquier `response_model`.
También puedes declarar la dependencia del parámetro `Response`, y establecer el código de estado en ellos. Pero ten en cuenta que el último en establecerse será el que gane.
También puedes declarar el parámetro `Response` en dependencias y establecer el código de estado en ellas. Pero ten en cuenta que el último establecido prevalecerá.
Cuando creas una *operación de path* normalmente puedes devolver cualquier dato: un `dict`, una `list`, un modelo Pydantic, un modelo de base de datos, etc.
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 devuelto a JSON usando el `jsonable_encoder` explicado en [Codificador Compatible JSON](../tutorial/encoder.md){.internal-link target=_blank}.
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}.
Luego, tras bastidores, pondría esos datos compatibles con JSON (por ejemplo, un `dict`) dentro de una`JSONResponse` que se usaría para enviar la respuesta al cliente.
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.
Pero puedes devolver una`JSONResponse` directamente de tu *operación de path*.
Pero puedes devolver un `JSONResponse` directamente desde tus *path operations*.
Esto puede ser útil, por ejemplo, para devolver cookies o headers personalizados.
Esto podría ser útil, por ejemplo, para devolver headers o cookies personalizados.
## Devolver una `Response`
De hecho, puedes devolver cualquier `Response` o cualquier subclase de la misma.
De hecho, puedes devolver cualquier `Response` o cualquier subclase de ella.
/// tip | Consejo
@ -22,44 +22,44 @@ De hecho, puedes devolver cualquier `Response` o cualquier subclase de la misma.
Y cuando devuelves una `Response`, **FastAPI** la pasará directamente.
No hará ninguna conversión de datos con modelos Pydantic, no convertirá el contenido a ningún tipo, etc.
No hará ninguna conversión de datos con los modelos de Pydantic, no convertirá los contenidos a ningún tipo, etc.
Esto te da mucha flexibilidad. Puedes devolver cualquier tipo de dato, sobrescribir cualquier declaración de datos o validación, etc.
Esto te da mucha flexibilidad. Puedes devolver cualquier tipo de datos, sobrescribir cualquier declaración o validación de datos, etc.
## Usando el `jsonable_encoder` en una `Response`
## Usar el `jsonable_encoder` en una `Response`
Como **FastAPI** no realiza ningún cambio en la `Response` que devuelves, debes asegurarte de que el contenido está listo.
Como **FastAPI** no realiza cambios en una `Response` que devuelves, tienes que asegurarte de que sus contenidos estén listos para ello.
Por ejemplo, no puedes poner un modelo Pydantic en una`JSONResponse` sin primero convertirlo a un `dict` con todos los tipos de datos (como `datetime`, `UUID`, etc) convertidos a tipos compatibles con JSON.
Por ejemplo, no puedes poner un modelo de Pydantic en un `JSONResponse` sin primero convertirlo a un `dict` con todos los tipos de datos (como `datetime`, `UUID`, etc.) convertidos a tipos compatibles con JSON.
Para esos casos, puedes usar el `jsonable_encoder` para convertir tus datos antes de pasarlos a la respuesta:
Para esos casos, puedes usar el `jsonable_encoder` para convertir tus datos antes de pasarlos a un response:
También puedes usar `from starlette.responses import JSONResponse`.
También podrías usar `from starlette.responses import JSONResponse`.
**FastAPI** provee `starlette.responses` como `fastapi.responses`, simplemente como una conveniencia para ti, el desarrollador. Pero la mayoría de las respuestas disponibles vienen directamente de Starlette.
**FastAPI** proporciona los mismos `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.
///
## Devolviendo una `Response` personalizada
## Devolver una `Response` personalizada
El ejemplo anterior muestra las partes que necesitas, pero no es muy útil todavía, dado que podrías simplemente devolver el `item` directamente, y **FastAPI** lo pondría en una `JSONResponse` por ti, convirtiéndolo en un `dict`, etc. Todo esto por defecto.
El ejemplo anterior muestra todas las partes que necesitas, pero aún no es muy útil, ya que podrías haber devuelto el `item` directamente, y **FastAPI** lo colocaría en un `JSONResponse` por ti, convirtiéndolo a un `dict`, etc. Todo eso por defecto.
Ahora, veamos cómo puedes usarlo para devolver una respuesta personalizada.
Ahora, veamos cómo podrías usar eso para devolver un response personalizado.
Digamos que quieres devolver una respuesta<ahref="https://en.wikipedia.org/wiki/XML"class="external-link"target="_blank">XML</a>.
Digamos que quieres devolver un response en<ahref="https://en.wikipedia.org/wiki/XML"class="external-link"target="_blank">XML</a>.
Podrías poner tu contenido XML en un string, ponerlo en una `Response` y devolverlo:
Podrías poner tu contenido XML en un string, poner eso en un `Response`, y devolverlo:
Cuando devuelves una `Response` directamente, los datos no son validados, convertidos (serializados), ni documentados automáticamente.
Cuando devuelves una `Response` directamente, sus datos no son validados, convertidos (serializados), ni documentados automáticamente.
Pero todavía es posible documentarlo como es descrito en [Respuestas adicionales en OpenAPI](additional-responses.md){.internal-link target=_blank}.
Pero aún puedes documentarlo como se describe en [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.
Puedes ver en secciones posteriores como usar/declarar esas `Response`s personalizadas aún teniendo conversión automática de datos, documentación, etc.
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.
Posteriormente, puedes devolver cualquier objeto que necesites, como normalmente harías (un `dict`, un modelo de base de datos, etc).
Y luego puedes devolver cualquier objeto que necesites, como harías normalmente (un `dict`, un modelo de base de datos, etc).
Si declaraste un `response_model`, este se continuará usando para filtrar y convertir el objeto que devolviste.
Y si declaraste un `response_model`, aún se usará para filtrar y convertir el objeto que devolviste.
**FastAPI** usará ese response *temporal* para extraer los headers (al igual que las cookies y el status code), además las pondrá en el response final que contendrá el valor retornado y filtrado por algún`response_model`.
**FastAPI** usará ese response *temporal* para extraer los headers (también cookies y el código de estado), y los pondrá en el response final que contiene el valor que devolviste, filtrado por cualquier`response_model`.
También puedes declarar el parámetro `Response` en dependencias, así como configurar los headers (y las cookies) en ellas.
También puedes declarar el parámetro `Response` en dependencias y establecer headers (y cookies) en ellas.
## Retorna una `Response` directamente
## Retornar una `Response` directamente
También puedes agregar headers cuando devuelves un `Response` directamente.
Adicionalmente, puedes añadir headers cuando se retorne una `Response` directamente.
Crea un response tal como se describe en [Retornar una respuesta 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){.internal-link target=_blank} y pasa los headers como un parámetro adicional:
También podrías utilizar `from starlette.responses import Response` o `from starlette.responses import JSONResponse`.
**FastAPI** proporciona las mismas `starlette.responses` en `fastapi.responses` sólo que de una manera más conveniente para ti, el desarrollador. En otras palabras, muchas de las responses disponibles provienen directamente de Starlette.
También podrías usar `from starlette.responses import Response` o `from starlette.responses import JSONResponse`.
**FastAPI** proporciona las mismas `starlette.responses` como `fastapi.responses` solo por conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles provienen directamente de Starlette.
Y como la `Response` puede ser usada frecuentemente para configurar headers y cookies, **FastAPI** también la provee en `fastapi.Response`.
Y como el `Response` se puede usar frecuentemente para establecer headers y cookies, **FastAPI** también lo proporciona en `fastapi.Response`.
///
## Headers Personalizados
Ten en cuenta que se pueden añadir headers propietarios personalizados <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 headers propietarios personalizados se pueden agregar<ahref="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers"class="external-link"target="_blank">usando el prefijo 'X-'</a>.
Si tienes headers personalizados y deseas que un cliente pueda verlos en el navegador, es necesario que los añadas a tus configuraciones de CORS (puedes leer más en [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), usando el parámetro `expose_headers` documentado en <ahref="https://www.starlette.io/middleware/#corsmiddleware"class="external-link"target="_blank">Starlette's CORS docs</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){.internal-link target=_blank}), usando el parámetro `expose_headers` documentado en <ahref="https://www.starlette.io/middleware/#corsmiddleware"class="external-link"target="_blank">la documentación CORS de Starlette</a>.
Hay algunas características adicionales para manejar la seguridad además de las que se tratan en el [Tutorial - Guía de 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){.internal-link target=_blank}.
/// tip | Consejo
Las siguientes secciones **no necesariamente son "avanzadas"**.
Las siguientes secciones **no son necesariamente "avanzadas"**.
Y es posible que para tu caso de uso, la solución esté en alguna de ellas.
Y es posible que para tu caso de uso, la solución esté en una de ellas.
///
## Leer primero el Tutorial
## Lee primero el Tutorial
En las siguientes secciones asumimos que ya has leído el principal [Tutorial - Guía de Usuario: Seguridad](../../tutorial/security/index.md){.internal-link target=_blank}.
Las siguientes secciones asumen que ya leíste el [Tutorial - Guía del Usuario: Seguridad](../../tutorial/security/index.md){.internal-link target=_blank}.
Están basadas en los mismos conceptos, pero permiten algunas funcionalidades adicionales.
Todas están basadas en los mismos conceptos, pero permiten algunas funcionalidades adicionales.
Detalles sobre la sintaxis `async def` para *path operation functions* y un poco de información sobre código asíncrono, concurrencia y paralelismo.
Detalles sobre la sintaxis `async def` para *path operation functions* y algunos antecedentes sobre el código asíncrono, la concurrencia y el paralelismo.
Si estás utilizando libraries de terceros que te dicen que las llames con `await`, del tipo:
Si estás usando paquetes de terceros que te dicen que los llames con `await`, como:
```Python
results = await some_library()
```
Entonces declara tus *path operation functions* con `async def`de la siguiente manera:
Entonces, declara tus *path operation functions* con `async def`así:
```Python hl_lines="2"
@app.get('/')
@ -29,7 +29,7 @@ Solo puedes usar `await` dentro de funciones creadas con `async def`.
---
Si estás utilizando libraries de terceros que se comunican con algo (una base de datos, una API, el sistema de archivos, etc.) y no tienes soporte para `await` (este es el caso para la mayoría de las libraries de bases de datos), declara tus *path operation functions* de forma habitual, con solo `def`, de la siguiente manera:
Si estás usando un paquete de terceros que se comunica con algo (una base de datos, una API, el sistema de archivos, etc.) y no tiene soporte para usar `await` (este es actualmente el caso para la mayoría de los paquetes de base de datos), entonces declara tus *path operation functions* como normalmente, usando simplemente `def`, así:
```Python hl_lines="2"
@app.get('/')
@ -40,7 +40,7 @@ def results():
---
Si tu aplicación (de alguna manera) no tiene que comunicarse con nada más y en consecuencia esperar a que responda, usa `async def`.
Si tu aplicación (de alguna manera) no tiene que comunicarse con nada más y esperar a que responda, usa `async def`.
---
@ -48,17 +48,17 @@ Si simplemente no lo sabes, usa `def` normal.
---
**Nota**: puedes mezclar `def` y `async def` en tus *path operation functions* tanto como lo necesites y definir cada una utilizando la mejor opción para ti. FastAPI hará lo correcto con ellos.
**Nota**: Puedes mezclar `def` y `async def` en tus *path operation functions* tanto como necesites y definir cada una utilizando la mejor opción para ti. FastAPI hará lo correcto con ellas.
De todos modos, en cualquiera de los casos anteriores, FastAPI seguirá funcionando de forma asíncrona y será extremadamente rápido.
Pero siguiendo los pasos anteriores, FastAPI podrá hacer algunas optimizaciones de rendimiento.
Pero al seguir los pasos anteriores, podrá hacer algunas optimizaciones de rendimiento.
## Detalles Técnicos
Las versiones modernas de Python tienen soporte para **"código asíncrono"** usando algo llamado **"coroutines"**, usando la sintaxis **`async` y `await`**.
Las versiones modernas de Python tienen soporte para **"código asíncrono"** utilizando algo llamado **"coroutines"**, con la sintaxis **`async` y `await`**.
Veamos esa frase por partes en las secciones siguientes:
Veamos esa frase por partes en las secciones a continuación:
* **Código Asíncrono**
* **`async` y `await`**
@ -66,203 +66,200 @@ Veamos esa frase por partes en las secciones siguientes:
## Código Asíncrono
El código asíncrono sólo significa que el lenguaje 💬 tiene una manera de decirle al sistema / programa 🤖 que, en algún momento del código, 🤖 tendrá que esperar a que *algo más* termine en otro sitio. Digamos que ese *algo más* se llama, por ejemplo, "archivo lento" 📝.
El código asíncrono simplemente significa que el lenguaje 💬 tiene una forma de decirle a la computadora / programa 🤖 que en algún momento del código, tendrá que esperar que *otra cosa* termine en otro lugar. Digamos que esa *otra cosa* se llama "archivo-lento" 📝.
Durante ese tiempo, el sistema puede hacer otras cosas, mientras "archivo lento" 📝 termina.
Entonces, durante ese tiempo, la computadora puede ir y hacer algún otro trabajo, mientras "archivo-lento" 📝 termina.
Entonces el sistema / programa 🤖 volverá cada vez que pueda, sea porque está esperando otra vez, porque 🤖 ha terminado todo el trabajo que tenía en ese momento. Y 🤖 verá si alguna de las tareas por las que estaba esperando ha terminado, haciendo lo que tenía que hacer.
Luego la computadora / programa 🤖 volverá cada vez que tenga una oportunidad porque está esperando nuevamente, o siempre que 🤖 haya terminado todo el trabajo que tenía en ese punto. Y 🤖 comprobará si alguna de las tareas que estaba esperando ya se han completado, haciendo lo que tenía que hacer.
Luego, 🤖 cogerá la primera tarea finalizada (digamos, nuestro "archivo lento" 📝) y continuará con lo que tenía que hacer con esa tarea.
Después, 🤖 toma la primera tarea que termine (digamos, nuestro "archivo-lento" 📝) y continúa con lo que tenía que hacer con ella.
Esa "espera de otra cosa" normalmente se refiere a operaciones<abbrtitle="Input and Output, en español: Entrada y Salida.">I/O</abbr> que son relativamente "lentas" (en relación a la velocidad del procesador y memoria RAM), como por ejemplo esperar por:
Ese "esperar otra cosa" normalmente se refiere a las operaciones de<abbrtitle="Input and Output">I/O</abbr> que son relativamente "lentas" (comparadas con la velocidad del procesador y la memoria RAM), como esperar:
* los datos de cliente que se envían a través de la red
* los datos enviados por tu programa para ser recibidos por el cliente a través de la red
* el contenido de un archivo en disco para ser leído por el sistema y entregado al programa
* los contenidos que tu programa da al sistema para ser escritos en disco
* una operación relacionada con una API remota
* una operación de base de datos
* el retorno de resultados de una consulta de base de datos
* que los datos del cliente se envíen a través de la red
* que los datos enviados por tu programa sean recibidos por el cliente a través de la red
* que el contenido de un archivo en el disco sea leído por el sistema y entregado a tu programa
* que el contenido que tu programa entregó al sistema sea escrito en el disco
* una operación de API remota
* que una operación de base de datos termine
* que una query de base de datos devuelva los resultados
* etc.
Como el tiempo de ejecución se consume principalmente al esperar a operaciones de <abbrtitle="Input and Output">I/O</abbr>, las llaman operaciones "<abbrtitle="atadas a Entrada y Salida">I/O bound</abbr>".
Como el tiempo de ejecución se consume principalmente esperando operaciones de <abbrtitle="Input and Output">I/O</abbr>, las llaman operaciones "I/O bound".
Se llama "asíncrono" porque el sistema / programa no tiene que estar "sincronizado" con la tarea lenta, esperando el momento exacto en que finaliza la tarea, sin hacer nada, para poder recoger el resultado de la tarea y continuar el trabajo.
Se llama "asíncrono" porque la computadora / programa no tiene que estar "sincronizado" con la tarea lenta, esperando el momento exacto en que la tarea termine, sin hacer nada, para poder tomar el resultado de la tarea y continuar el trabajo.
En lugar de eso, al ser un sistema "asíncrono", una vez finalizada, la tarea puede esperar un poco en la cola (algunos microsegundos) para que la computadora / programa termine lo que estaba haciendo, y luego vuelva para recoger los resultados y seguir trabajando con ellos.
En lugar de eso, al ser un sistema "asíncrono", una vez terminado, la tarea puede esperar un poco en la cola (algunos microsegundos) para que la computadora / programa termine lo que salió a hacer, y luego regrese para tomar los resultados y continuar trabajando con ellos.
Por "síncrono" (contrario a "asíncrono") también se usa habitualmente el término "secuencial", porque el sistema / programa sigue todos los pasos secuencialmente antes de cambiar a una tarea diferente, incluso si esos pasos implican esperas.
Para el "sincrónico" (contrario al "asíncrono") comúnmente también usan el término "secuencial", porque la computadora / programa sigue todos los pasos en secuencia antes de cambiar a una tarea diferente, incluso si esos pasos implican esperar.
### Concurrencia y Hamburguesas
El concepto de código **asíncrono** descrito anteriormente a veces también se llama **"concurrencia"**. Es diferente del **"paralelismo"**.
Esta idea de código **asíncrono** descrita anteriormente a veces también se llama **"concurrencia"**. Es diferente del **"paralelismo"**.
**Concurrencia** y **paralelismo** ambos se relacionan con "cosas diferentes que suceden más o menos al mismo tiempo".
**Concurrencia** y **paralelismo** ambos se relacionan con "diferentes cosas sucediendo más o menos al mismo tiempo".
Pero los detalles entre *concurrencia* y *paralelismo* son bastante diferentes.
Para entender las diferencias, imagina la siguiente historia sobre hamburguesas:
Para ver la diferencia, imagina la siguiente historia sobre hamburguesas:
### Hamburguesas Concurrentes
Vas con la persona que te gusta 😍 a pedir comida rápida 🍔, haces cola mientras el cajero 💁 recoge los pedidos de las personas de delante tuyo.
Vas con tu crush a conseguir comida rápida, te pones en fila mientras el cajero toma los pedidos de las personas frente a ti. 😍
El cajero 💁 le dice algo al chico de la cocina 👨🍳 para que sepa que tiene que preparar tus hamburguesas 🍔 (a pesar de que actualmente está preparando las de los clientes anteriores).
El cajero dice algo al cocinero en la cocina para que sepan que tienen que preparar tus hamburguesas (aunque actualmente están preparando las de los clientes anteriores).
Mientras esperas, vas con esa persona 😍 y eliges una mesa, se sientan y hablan durante un rato largo (ya que las hamburguesas son muy impresionantes y necesitan un rato para prepararse ✨🍔✨).
Mientras esperas, vas con tu crush y eliges una mesa, te sientas y hablas con tu crush por un largo rato (ya que tus hamburguesas son muy sofisticadas y toman un tiempo en prepararse).
Mientras te sientas en la mesa con esa persona 😍, esperando las hamburguesas 🍔, puedes disfrutar ese tiempo admirando lo increíble, inteligente, y bien que se ve ✨😍✨.
Mientras estás sentado en la mesa con tu crush, mientras esperas las hamburguesas, puedes pasar ese tiempo admirando lo increíble, lindo e inteligente que es tu crush ✨😍✨.
Imagina que eres el sistema / programa 🤖 en esa historia.
Imagina que eres la computadora / programa 🤖 en esa historia.
Mientras estás en la cola, estás quieto 😴, esperando tu turno, sin hacer nada muy "productivo". Pero la línea va rápida porque el cajero 💁 solo recibe los pedidos (no los prepara), así que está bien.
Mientras estás en la fila, estás inactivo 😴, esperando tu turno, sin hacer nada muy "productivo". Pero la fila es rápida porque el cajero solo está tomando los pedidos (no preparándolos), así que está bien.
Luego, cuando llega tu turno, haces un trabajo "productivo" real 🤓, procesas el menú, decides lo que quieres, lo que quiere esa persona 😍, pagas 💸, verificas que das el billete o tarjeta correctos, verificas que te cobren correctamente, que el pedido tiene los artículos correctos, etc.
Luego, cuando es tu turno, haces un trabajo realmente "productivo", procesas el menú, decides lo que quieres, obtienes la elección de tu crush, pagas, verificas que das el billete o tarjeta correctos, verificas que te cobren correctamente, verificas que el pedido tenga los artículos correctos, etc.
Pero entonces, aunque aún no tienes tus hamburguesas 🍔, el trabajo hecho con el cajero 💁 está "en pausa" ⏸, porque debes esperar 🕙 a que tus hamburguesas estén listas.
Pero luego, aunque todavía no tienes tus hamburguesas, tu trabajo con el cajero está "en pausa" ⏸, porque tienes que esperar 🕙 a que tus hamburguesas estén listas.
Pero como te alejas del mostrador y te sientas en la mesa con un número para tu turno, puedes cambiar tu atención 🔀 a esa persona 😍 y "trabajar" ⏯ 🤓 en eso. Entonces nuevamente estás haciendo algo muy "productivo" 🤓, como coquetear con esa persona 😍.
Pero como te alejas del mostrador y te sientas en la mesa con un número para tu turno, puedes cambiar 🔀 tu atención a tu crush, y "trabajar" ⏯ 🤓 en eso. Luego, nuevamente estás haciendo algo muy "productivo" como es coquetear con tu crush 😍.
Después, el 💁 cajero dice "he terminado de hacer las hamburguesas" 🍔 poniendo tu número en la pantalla del mostrador, pero no saltas al momento que el número que se muestra es el tuyo. Sabes que nadie robará tus hamburguesas 🍔 porque tienes el número de tu turno y ellos tienen el suyo.
Luego el cajero 💁 dice "he terminado de hacer las hamburguesas" al poner tu número en el mostrador, pero no saltas como loco inmediatamente cuando el número mostrado cambia a tu número de turno. Sabes que nadie robará tus hamburguesas porque tienes el número de tu turno, y ellos tienen el suyo.
Así que esperas a que esa persona 😍 termine la historia (terminas el trabajo actual ⏯ / tarea actual que se está procesando 🤓), sonríes gentilmente y le dices que vas por las hamburguesas ⏸.
Así que esperas a que tu crush termine la historia (termine el trabajo ⏯ / tarea actual que se está procesando 🤓), sonríes amablemente y dices que vas por las hamburguesas ⏸.
Luego vas al mostrador 🔀, a la tarea inicial que ya está terminada ⏯, recoges las hamburguesas 🍔, les dices gracias y las llevas a la mesa. Eso termina esa fase / tarea de interacción con el mostrador ⏹. Eso a su vez, crea una nueva tarea, "comer hamburguesas" 🔀 ⏯, pero la anterior de "conseguir hamburguesas" está terminada ⏹.
Luego vas al mostrador 🔀, a la tarea inicial que ahora está terminada ⏯, recoges las hamburguesas, das las gracias y las llevas a la mesa. Eso termina ese paso / tarea de interacción con el mostrador ⏹. Eso a su vez, crea una nueva tarea, de "comer hamburguesas" 🔀 ⏯, pero la anterior de "obtener hamburguesas" ha terminado ⏹.
### Hamburguesas Paralelas
Ahora imagina que estas no son "Hamburguesas Concurrentes" sino "Hamburguesas Paralelas".
Ahora imaginemos que estas no son "Hamburguesas Concurrentes", sino "Hamburguesas Paralelas".
Vas con la persona que te gusta 😍 por comida rápida paralela 🍔.
Vas con tu crush a obtener comida rápida paralela.
Haces la cola mientras varios cajeros (digamos 8) que a la vez son cocineros 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳 toman los pedidos de las personas que están delante de ti.
Te pones en fila mientras varios (digamos 8) cajeros que al mismo tiempo son cocineros toman los pedidos de las personas frente a ti.
Todos los que están antes de ti están esperando 🕙 que sus hamburguesas 🍔 estén listas antes de dejar el mostrador porque cada uno de los 8 cajeros prepara la hamburguesa de inmediato antes de recibir el siguiente pedido.
Todos antes que tú están esperando a que sus hamburguesas estén listas antes de dejar el mostrador porque cada uno de los 8 cajeros va y prepara la hamburguesa de inmediato antes de obtener el siguiente pedido.
Como tu y esa persona 😍 están ocupados en impedir que alguien se ponga delante y recoja tus hamburguesas apenas llegan 🕙, tampoco puedes prestarle atención a esa persona 😞.
Como tú y tu crush están ocupados no dejando que nadie se interponga y tome tus hamburguesas cuando lleguen, no puedes prestar atención a tu crush. 😞
Este es un trabajo "síncrono", estás "sincronizado" con el cajero/cocinero 👨🍳. Tienes que esperar y estar allí en el momento exacto en que el cajero / cocinero 👨🍳 termina las hamburguesas 🍔 y te las da, o de lo contrario, alguien más podría cogerlas.
Este es un trabajo "sincrónico", estás "sincronizado" con el cajero/cocinero 👨🍳. Tienes que esperar 🕙 y estar allí en el momento exacto en que el cajero/cocinero 👨🍳 termine las hamburguesas y te las entregue, o de lo contrario, alguien más podría tomarlas.
En este escenario de las hamburguesas paralelas, tú eres un sistema / programa 🤖 con dos procesadores (tú y la persona que te gusta 😍), ambos esperando 🕙 y dedicando su atención ⏯ a estar "esperando en el mostrador" 🕙 durante mucho tiempo.
En este escenario de las hamburguesas paralelas, eres una computadora / programa 🤖 con dos procesadores (tú y tu crush), ambos esperando 🕙 y dedicando su atención ⏯ a estar "esperando en el mostrador" 🕙 por mucho tiempo.
La tienda de comida rápida tiene 8 procesadores (cajeros/cocineros) 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳. Mientras que la tienda de hamburguesas concurrentes podría haber tenido solo 2 (un cajero y un cocinero) 💁 👨🍳.
La tienda de comida rápida tiene 8 procesadores (cajeros/cocineros). Mientras que la tienda de hamburguesas concurrentes podría haber tenido solo 2 (un cajero y un cocinero).
Pero aún así, la experiencia final no es la mejor 😞.
Pero aún así, la experiencia final no es la mejor. 😞
---
Esta sería la historia paralela equivalente de las hamburguesas 🍔.
Esta sería la historia equivalente de las hamburguesas paralelas. 🍔
Para un ejemplo más "real" de ésto, imagina un banco.
Para un ejemplo más "de la vida real" de esto, imagina un banco.
Hasta hace poco, la mayoría de los bancos tenían varios cajeros 👨💼👨💼👨💼👨💼 y una gran línea 🕙🕙🕙🕙🕙🕙🕙🕙.
Hasta hace poco, la mayoría de los bancos tenían múltiples cajeros 👨💼👨💼👨💼👨💼 y una gran fila 🕙🕙🕙🕙🕙🕙🕙🕙.
Todos los cajeros haciendo todo el trabajo con un cliente tras otro 👨💼⏯.
Y tienes que esperar 🕙 en la fila durante mucho tiempo o perderás tu turno.
Probablemente no querrás llevar contigo a la persona que te gusta 😍 a hacer encargos al banco 🏦.
Y tienes que esperar 🕙 en la fila por mucho tiempo o pierdes tu turno.
### Conclusión de las Hamburguesa
Probablemente no querrías llevar a tu crush 😍 contigo a hacer trámites en el banco 🏦.
En este escenario de "hamburguesas de comida rápida con tu pareja", debido a que hay mucha espera 🕙, tiene mucho más sentido tener un sistema con concurrencia ⏸🔀⏯.
### Conclusión de las Hamburguesas
Este es el caso de la mayoría de las aplicaciones web.
En este escenario de "hamburguesas de comida rápida con tu crush", como hay mucha espera 🕙, tiene mucho más sentido tener un sistema concurrente ⏸🔀⏯.
Muchos, muchos usuarios, pero el servidor está esperando 🕙 el envío de las peticiones ya que su conexión no es buena.
Este es el caso para la mayoría de las aplicaciones web.
Y luego esperando 🕙 nuevamente a que las respuestas retornen.
Muchos, muchos usuarios, pero tu servidor está esperando 🕙 su conexión no tan buena para enviar sus requests.
Esta "espera" 🕙 se mide en microsegundos, pero aun así, sumando todo, al final es mucha espera.
Y luego esperar 🕙 nuevamente a que los responses regresen.
Es por eso que tiene mucho sentido usar código asíncrono ⏸🔀⏯ para las API web.
Esta "espera" 🕙 se mide en microsegundos, pero aún así, sumándolo todo, es mucha espera al final.
La mayoría de los framework populares de Python existentes (incluidos Flask y Django) se crearon antes de que existieran las nuevas funciones asíncronas en Python. Por lo tanto, las formas en que pueden implementarse admiten la ejecución paralela y una forma más antigua de ejecución asíncrona que no es tan potente como la actual.
Por eso tiene mucho sentido usar código asíncrono ⏸🔀⏯ para las APIs web.
A pesar de que la especificación principal para Python web asíncrono (ASGI) se desarrolló en Django, para agregar soporte para WebSockets.
Ese tipo de asincronía es lo que hizo popular a NodeJS (aunque NodeJS no es paralelo) y esa es la fortaleza de Go como lenguaje de programación.
Este tipo de asincronía es lo que hizo popular a NodeJS (aunque NodeJS no es paralelo) y esa es la fortaleza de Go como lenguaje de programación.
Y ese es el mismo nivel de rendimiento que obtienes con **FastAPI**.
Y como puede tener paralelismo y asincronía al mismo tiempo, obtienes un mayor rendimiento que la mayoría de los frameworks de NodeJS probados y a la par con Go, que es un lenguaje compilado más cercano a C <ahref="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1"class="external-link"target="_blank">(todo gracias Starlette)</a>.
Y como puedes tener paralelismo y asincronía al mismo tiempo, obtienes un mayor rendimiento que la mayoría de los frameworks de NodeJS probados y a la par con Go, que es un lenguaje compilado más cercano a C <ahref="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1"class="external-link"target="_blank">(todo gracias a Starlette)</a>.
### ¿Es la concurrencia mejor que el paralelismo?
¡No! Esa no es la moraleja de la historia.
La concurrencia es diferente al paralelismo. Y es mejor en escenarios **específicos** que implican mucha espera. Debido a eso, generalmente es mucho mejor que el paralelismo para el desarrollo de aplicaciones web. Pero no para todo.
La concurrencia es diferente del paralelismo. Y es mejor en escenarios **específicos** que implican mucha espera. Debido a eso, generalmente es mucho mejor que el paralelismo para el desarrollo de aplicaciones web. Pero no para todo.
Entonces, para explicar eso, imagina la siguiente historia corta:
Así que, para equilibrar eso, imagina la siguiente historia corta:
> Tienes que limpiar una casa grande y sucia.
@ -270,80 +267,80 @@ Entonces, para explicar eso, imagina la siguiente historia corta:
---
No hay esperas 🕙, solo hay mucho trabajo por hacer, en varios lugares de la casa.
No hay esperas 🕙 en ninguna parte, solo mucho trabajo por hacer, en múltiples lugares de la casa.
Podrías tener turnos como en el ejemplo de las hamburguesas, primero la sala de estar, luego la cocina, pero como no estás esperando nada, solo limpiando y limpiando, los turnos no afectarían nada.
Podrías tener turnos como en el ejemplo de las hamburguesas, primero la sala de estar, luego la cocina, pero como no estás esperando 🕙 nada, solo limpiando y limpiando, los turnos no afectarían nada.
Tomaría la misma cantidad de tiempo terminar con o sin turnos (concurrencia) y habrías hecho la misma cantidad de trabajo.
Pero en este caso, si pudieras traer a los 8 ex cajeros / cocineros / ahora limpiadores 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳, y cada uno de ellos (y tú) podría tomar una zona de la casa para limpiarla, podría hacer todo el trabajo en **paralelo**, con la ayuda adicional y terminar mucho antes.
Pero en este caso, si pudieras traer a los 8 ex-cajeros/cocineros/ahora-limpiadores, y cada uno de ellos (más tú) pudiera tomar una zona de la casa para limpiarla, podrías hacer todo el trabajo en **paralelo**, con la ayuda extra, y terminar mucho antes.
En este escenario, cada uno de los limpiadores (incluido tú) sería un procesador, haciendo su parte del trabajo.
En este escenario, cada uno de los limpiadores (incluyéndote) sería un procesador, haciendo su parte del trabajo.
Y como la mayor parte del tiempo de ejecución lo coge el trabajo real (en lugar de esperar), y el trabajo en un sistema lo realiza una <abbrtitle="Central Processing Unit. En español: Unidad Central de Procesamiento.">CPU</abbr>, a estos problemas se les llama "<abbrtitle="En español: atado a CPU.">CPU bound</abbr>".
Y como la mayor parte del tiempo de ejecución se dedica al trabajo real (en lugar de esperar), y el trabajo en una computadora lo realiza una <abbrtitle="Central Processing Unit">CPU</abbr>, llaman a estos problemas "CPU bound".
---
Ejemplos típicos de operaciones dependientes de CPU son cosas que requieren un procesamiento matemático complejo.
Ejemplos comunes de operaciones limitadas por la CPU son cosas que requieren procesamiento matemático complejo.
Por ejemplo:
* **Audio** o **procesamiento de imágenes**.
* **Visión por computadora**: una imagen está compuesta de millones de píxeles, cada píxel tiene 3 valores / colores, procesamiento que normalmente requiere calcular algo en esos píxeles, todo al mismo tiempo.
* **Machine Learning**: normalmente requiere muchas multiplicaciones de "matrices" y "vectores". Imagina en una enorme hoja de cálculo con números y tener que multiplicarlos todos al mismo tiempo.
* **Deep Learning**: este es un subcampo de Machine Learning, por lo tanto, aplica lo mismo. Es solo que no hay una sola hoja de cálculo de números para multiplicar, sino un gran conjunto de ellas, y en muchos casos, usa un procesador especial para construir y / o usar esos modelos.
* **Procesamiento de audio** o **imágenes**.
* **Visión por computadora**: una imagen está compuesta de millones de píxeles, cada píxel tiene 3 valores / colores, procesar eso normalmente requiere calcular algo en esos píxeles, todos al mismo tiempo.
* **Machine Learning**: normalmente requiere muchas multiplicaciones de "matrices" y "vectores". Piensa en una enorme hoja de cálculo con números y multiplicando todos juntos al mismo tiempo.
* **Deep Learning**: este es un subcampo de Machine Learning, por lo tanto, se aplica lo mismo. Es solo que no hay una sola hoja de cálculo de números para multiplicar, sino un enorme conjunto de ellas, y en muchos casos, usas un procesador especial para construir y / o usar esos modelos.
### Concurrencia + Paralelismo: Web + Machine Learning
Con **FastAPI** puedes aprovechar la concurrencia que es muy común para el desarrollo web (atractivo principal de NodeJS).
Con **FastAPI** puedes aprovechar la concurrencia que es muy común para el desarrollo web (la misma atracción principal de NodeJS).
Pero también puedes aprovechar los beneficios del paralelismo y el multiprocesamiento (tener múltiples procesos ejecutándose en paralelo) para cargas de trabajo **CPU bound** como las de los sistemas de Machine Learning.
Pero también puedes explotar los beneficios del paralelismo y la multiprocesamiento (tener múltiples procesos ejecutándose en paralelo) para cargas de trabajo **CPU bound** como las de los sistemas de Machine Learning.
Eso, más el simple hecho de que Python es el lenguaje principal para **Data Science**, Machine Learning y especialmente Deep Learning, hacen de FastAPI una muy buena combinación para las API y aplicaciones web de Data Science / Machine Learning (entre muchas otras).
Eso, más el simple hecho de que Python es el lenguaje principal para **Data Science**, Machine Learning y especialmente Deep Learning, hacen de FastAPI una muy buena opción para APIs web de Data Science / Machine Learning y aplicaciones (entre muchas otras).
Para ver cómo lograr este paralelismo en producción, consulta la sección sobre [Despliegue](deployment/index.md){.internal-link target=_blank}.
Para ver cómo lograr este paralelismo en producción, consulta la sección sobre [Deployment](deployment/index.md){.internal-link target=_blank}.
## `async` y `await`
Las versiones modernas de Python tienen una forma muy intuitiva de definir código asíncrono. Esto hace que se vea como un código "secuencial" normal y que haga la "espera" por ti en los momentos correctos.
Las versiones modernas de Python tienen una forma muy intuitiva de definir código asíncrono. Esto hace que se vea igual que el código "secuencial" normal y hace el "wait" por ti en los momentos adecuados.
Cuando hay una operación que requerirá esperar antes de dar los resultados y tiene soporte para estas nuevas características de Python, puedes programarlo como:
Cuando hay una operación que requerirá esperar antes de dar los resultados y tiene soporte para estas nuevas funcionalidades de Python, puedes programarlo así:
```Python
burgers = await get_burgers(2)
```
La clave aquí es `await`. Eso le dice a Python que tiene que esperar ⏸ a que `get_burgers (2)` termine de hacer lo suyo 🕙 antes de almacenar los resultados en `hamburguesas`. Con eso, Python sabrá que puede ir y hacer otra cosa 🔀 ⏯ mientras tanto (como recibir otra solicitud).
La clave aquí es el `await`. Dice a Python que tiene que esperar ⏸ a que `get_burgers(2)` termine de hacer su cosa 🕙 antes de almacenar los resultados en `burgers`. Con eso, Python sabrá que puede ir y hacer algo más 🔀 ⏯ mientras tanto (como recibir otro request).
Para que `await` funcione, tiene que estar dentro de una función que admita esta asincronía. Para hacer eso, simplemente lo declaras con `async def`:
Para que `await` funcione, tiene que estar dentro de una función que soporte esta asincronía. Para hacer eso, solo declara la función con `async def`:
```Python hl_lines="1"
async def get_burgers(number: int):
# Do some asynchronous stuff to create the burgers
# Hacer algunas cosas asíncronas para crear las hamburguesas
return burgers
```
...en vez de `def`:
...en lugar de `def`:
```Python hl_lines="2"
# This is not asynchronous
# Esto no es asíncrono
def get_sequential_burgers(number: int):
# Do some sequential stuff to create the burgers
# Hacer algunas cosas secuenciales para crear las hamburguesas
return burgers
```
Con `async def`, Python sabe que, dentro de esa función, debe tener en cuenta las expresiones `wait` y que puede "pausar" ⏸ la ejecución de esa función e ir a hacer otra cosa 🔀 antes de regresar.
Con `async def`, Python sabe que, dentro de esa función, tiene que estar atento a las expresiones `await`, y que puede "pausar" ⏸ la ejecución de esa función e ir a hacer algo más 🔀 antes de regresar.
Cuando desees llamar a una función `async def`, debes "esperarla". Entonces, esto no funcionará:
Cuando deseas llamar a una función `async def`, tienes que "await" dicha función. Así que, esto no funcionará:
```Python
# Esto no funcionará, porque get_burgers se definió con: async def
hamburguesas = get_burgers (2)
# Esto no funcionará, porque get_burgers fue definido con: async def
burgers = get_burgers(2)
```
---
Por lo tanto, si estás utilizando una library que te dice que puedes llamarla con `await`, debes crear las *path operation functions* que la usan con `async def`, como en:
Así que, si estás usando un paquete que te dice que puedes llamarlo con `await`, necesitas crear las *path operation functions* que lo usen con `async def`, como en:
```Python hl_lines="2-3"
@app.get('/burgers')
@ -354,15 +351,25 @@ async def read_burgers():
### Más detalles técnicos
Es posible que hayas notado que `await` solo se puede usar dentro de las funciones definidas con `async def`.
Podrías haber notado que `await` solo se puede usar dentro de funciones definidas con `async def`.
Pero al mismo tiempo, las funciones definidas con `async def` deben ser "awaited". Por lo tanto, las funciones con `async def` solo se pueden llamar dentro de funciones definidas con `async def` también.
Entonces, sobre el huevo y la gallina, ¿cómo llamas a la primera función `async`?
Si estás trabajando con **FastAPI** no tienes que preocuparte por eso, porque esa "primera" función será tu *path operation function*, y FastAPI sabrá cómo hacer lo correcto.
Pero si deseas usar `async` / `await` sin FastAPI, también puedes hacerlo.
### Escribe tu propio código async
Pero al mismo tiempo, las funciones definidas con `async def` deben ser "esperadas". Por lo tanto, las funciones con `async def` solo se pueden invocar dentro de las funciones definidas con `async def` también.
Starlette (y **FastAPI**) están basados en <ahref="https://anyio.readthedocs.io/en/stable/"class="external-link"target="_blank">AnyIO</a>, lo que lo hace compatible tanto con la librería estándar de Python <ahref="https://docs.python.org/3/library/asyncio-task.html"class="external-link"target="_blank">asyncio</a> como con <ahref="https://trio.readthedocs.io/en/stable/"class="external-link"target="_blank">Trio</a>.
Entonces, relacionado con la paradoja del huevo y la gallina, ¿cómo se llama a la primera función `async`?
En particular, puedes usar directamente <ahref="https://anyio.readthedocs.io/en/stable/"class="external-link"target="_blank">AnyIO</a> para tus casos de uso avanzados de concurrencia que requieran patrones más avanzados en tu propio código.
Si estás trabajando con **FastAPI** no tienes que preocuparte por eso, porque esa "primera" función será tu *path operation function*, y FastAPI sabrá cómo hacer lo pertinente.
E incluso si no estuvieras usando FastAPI, también podrías escribir tus propias aplicaciones asíncronas con <ahref="https://anyio.readthedocs.io/en/stable/"class="external-link"target="_blank">AnyIO</a> para ser altamente compatibles y obtener sus beneficios (p.ej. *concurrencia estructurada*).
En el caso de que desees usar `async` / `await` sin FastAPI, <ahref="https://docs.python.org/3/library/asyncio-task.html#coroutine"class="external-link"target="_blank">revisa la documentación oficial de Python</a>.
Creé otro paquete sobre AnyIO, como una capa delgada, para mejorar un poco las anotaciones de tipos y obtener mejor **autocompletado**, **errores en línea**, etc. También tiene una introducción amigable y tutorial para ayudarte a **entender** y escribir **tu propio código async**:<ahref="https://asyncer.tiangolo.com/"class="external-link"target="_blank">Asyncer</a>. Sería particularmente útil si necesitas **combinar código async con regular** (bloqueante/sincrónico).
### Otras formas de código asíncrono
@ -370,68 +377,68 @@ Este estilo de usar `async` y `await` es relativamente nuevo en el lenguaje.
Pero hace que trabajar con código asíncrono sea mucho más fácil.
Esta misma sintaxis (o casi idéntica) también se incluyó recientemente en las versiones modernas de JavaScript (en Browser y NodeJS).
Esta misma sintaxis (o casi idéntica) también se incluyó recientemente en las versiones modernas de JavaScript (en el Navegador y NodeJS).
Pero antes de eso, manejar código asíncrono era bastante más complejo y difícil.
Pero antes de eso, manejar el código asíncrono era mucho más complejo y difícil.
En versiones anteriores de Python, podrías haber utilizado <abbrtitle="En español: hilos.">threads</abbr> o <ahref="https://www.gevent.org/"class="external-link"target="_blank">Gevent</a>. Pero el código es mucho más complejo de entender, depurar y desarrollar.
En versiones previas de Python, podrías haber usado hilos o <ahref="https://www.gevent.org/"class="external-link"target="_blank">Gevent</a>. Pero el código es mucho más complejo de entender, depurar y razonar.
En versiones anteriores de NodeJS / Browser JavaScript, habrías utilizado "callbacks". Lo que conduce a<ahref="http://callbackhell.com/"class="external-link"target="_blank">callback hell</a>.
En versiones previas de NodeJS / JavaScript en el Navegador, habrías usado "callbacks". Lo que lleva al<ahref="http://callbackhell.com/"class="external-link"target="_blank">callback hell</a>.
## Coroutines
**Coroutine** es un término sofisticado para referirse a la cosa devuelta por una función `async def`. Python sabe que es algo así como una función que puede iniciar y que terminará en algún momento, pero que también podría pausarse ⏸ internamente, siempre que haya un `await` dentro de ella.
**Coroutines** es simplemente el término muy elegante para la cosa que devuelve una función `async def`. Python sabe que es algo parecido a una función, que puede comenzar y que terminará en algún momento, pero que podría pausar ⏸ internamente también, siempre que haya un `await` dentro de él.
Pero toda esta funcionalidad de usar código asincrónico con `async` y `await` se resume muchas veces como usar "coroutines". Es comparable a la característica principal de Go, las "Goroutines".
Pero toda esta funcionalidad de usar código asíncrono con `async` y `await` a menudo se resume como utilizar "coroutines". Es comparable a la funcionalidad clave principal de Go, las "Goroutines".
## Conclusión
Veamos la misma frase de arriba:
> Las versiones modernas de Python tienen soporte para **"código asíncrono"** usando algo llamado **"coroutines"**, con la sintaxis **`async` y `await`**.
> Las versiones modernas de Python tienen soporte para **"código asíncrono"** utilizando algo llamado **"coroutines"**, con la sintaxis **`async` y `await`**.
Eso ya debería tener más sentido ahora. ✨
Eso debería tener más sentido ahora. ✨
Todo eso es lo que impulsa FastAPI (a través de Starlette) y lo que hace que tenga un rendimiento tan impresionante.
## Detalles muy técnicos
## Detalles Muy Técnicos
/// warning | Advertencia
Probablemente puedas saltarte esto.
Estos son detalles muy técnicos de cómo **FastAPI** funciona a muy bajo nivel.
Estos son detalles muy técnicos de cómo funciona **FastAPI** en su interior.
Si tienes bastante conocimiento técnico (coroutines, threads, bloqueos, etc.) y tienes curiosidad acerca de cómo FastAPI gestiona `async def` vs `def` normal, continúa.
Si tienes bastante conocimiento técnico (coroutines, hilos, bloqueo, etc.) y tienes curiosidad sobre cómo FastAPI maneja `async def` vs `def` normal, adelante.
///
### Path operation functions
### Funciones de *path operation*
Cuando declaras una *path operation function* con `def` normal en lugar de `async def`, se ejecuta en un threadpool externo que luego es "<abbrtitle="En español: esperado. Usando await.">awaited</abbr>", en lugar de ser llamado directamente (ya que bloquearía el servidor).
Cuando declaras una *path operation function* con `def` normal en lugar de `async def`, se ejecuta en un threadpool externo que luego es esperado, en lugar de ser llamado directamente (ya que bloquearía el servidor).
Si vienes de otro framework asíncrono que no funciona de la manera descrita anteriormente y estás acostumbrado a definir *path operation functions* del tipo sólo cálculo con `def` simple para una pequeña ganancia de rendimiento (aproximadamente 100 nanosegundos), ten en cuenta que en **FastAPI** el efecto sería bastante opuesto. En estos casos, es mejor usar `async def` a menos que tus *path operation functions* usen un código que realice el bloqueo<abbrtitle="Input/Output: disk reading or writing, network communications.">I/O</abbr>.
Si vienes de otro framework async que no funciona de la manera descrita anteriormente y estás acostumbrado a definir funciones de *path operation* solo de cómputo trivial con `def` normal para una pequeña ganancia de rendimiento (alrededor de 100 nanosegundos), ten en cuenta que en **FastAPI** el efecto sería bastante opuesto. En estos casos, es mejor usar `async def` a menos que tus *path operation functions* usen código que realice <abbrtitle="Input/Output: lectura o escritura en disco, comunicaciones de red.">I/O</abbr> de bloqueo.
Aún así, en ambas situaciones, es probable que **FastAPI** sea [aún más rápido](index.md#rendimiento){.Internal-link target=_blank} que (o al menos comparable) a tu framework anterior.
Aun así, en ambas situaciones, es probable que **FastAPI** [siga siendo más rápida](index.md#performance){.internal-link target=_blank} que (o al menos comparable a) tu framework anterior.
### Dependencias
Lo mismo se aplica para las dependencias. Si una dependencia es una función estándar `def` en lugar de `async def`, se ejecuta en el threadpool externo.
Lo mismo aplica para las [dependencias](tutorial/dependencies/index.md){.internal-link target=_blank}. Si una dependencia es una función estándar `def` en lugar de `async def`, se ejecuta en el threadpool externo.
### Subdependencias
### Sub-dependencias
Puedes tener múltiples dependencias y subdependencias que se requieren unas a otras (como parámetros de las definiciones de cada función), algunas de ellas pueden crearse con `async def` y otras con `def` normal. Igual todo seguiría funcionando correctamente, y las creadas con `def` normal se llamarían en un thread externo (del threadpool) en lugar de ser "awaited".
Puedes tener múltiples dependencias y [sub-dependencias](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} requiriéndose mutuamente (como parámetros de las definiciones de funciones), algunas de ellas podrían ser creadas con `async def` y algunas con `def` normal. Aun funcionará, y las que fueron creadas con `def` normal serían llamadas en un hilo externo (del threadpool) en lugar de ser "awaited".
### Otras funciones de utilidades
### Otras funciones de utilidad
Cualquier otra función de utilidad que llames directamente se puede crear con `def` o `async def` normales y FastAPI no afectará la manera en que la llames.
Cualquier otra función de utilidad que llames directamente puede ser creada con `def` normal o `async def` y FastAPI no afectará la forma en que la llames.
Esto contrasta con las funciones que FastAPI llama por ti: las *path operation functions* y dependencias.
Esto contrasta con las funciones que FastAPI llama por ti: *path operation functions* y dependencias.
Si tu función de utilidad es creada con `def` normal, se llamará directamente (tal cual la escribes en tu código), no en un threadpool, si la función se crea con `async def`, entonces debes usar `await` con esa función cuando la llamas en tu código.
Si tu función de utilidad es una función normal con `def`, será llamada directamente (como la escribas en tu código), no en un threadpool; si la función es creada con `async def` entonces deberías "await" por esa función cuando la llames en tu código.
---
Nuevamente, estos son detalles muy técnicos que probablemente sólo son útiles si los viniste a buscar expresamente.
Nuevamente, estos son detalles muy técnicos que probablemente serían útiles si los buscaste.
De lo contrario, la guía de la sección anterior debería ser suficiente: <ahref="#in-a-hurry">¿Tienes prisa?</a>.
De lo contrario, deberías estar bien con las pautas de la sección anterior: <ahref="#in-a-hurry">¿Con prisa?</a>.
Los benchmarks independientes de TechEmpower muestran aplicaciones de **FastAPI**que se ejecutan en Uvicorn como <ahref="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7"class="external-link"target="_blank">uno de los frameworks de Python más rápidos disponibles</a>, solo por debajo de Starlette y Uvicorn (utilizados internamente por FastAPI). (*)
Los benchmarks independientes de TechEmpower muestran aplicaciones de **FastAPI**ejecutándose bajo Uvicorn como <ahref="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7"class="external-link"target="_blank">uno de los frameworks de Python más rápidos disponibles</a>, solo por debajo de Starlette y Uvicorn en sí mismos (utilizados internamente por FastAPI).
Pero al comprobar benchmarks y comparaciones debes tener en cuenta lo siguiente.
Pero al revisar benchmarks y comparaciones, debes tener en cuenta lo siguiente.
## Benchmarks y velocidad
Cuando revisas los benchmarks, es común ver varias herramientas de diferentes tipos comparadas como equivalentes.
Cuando ves los benchmarks, es común ver varias herramientas de diferentes tipos comparadas como equivalentes.
Específicamente, para ver Uvicorn, Starlette y FastAPI comparadas entre sí (entre muchas otras herramientas).
Específicamente, ver Uvicorn, Starlette y FastAPI comparados juntos (entre muchas otras herramientas).
Cuanto más sencillo sea el problema resuelto por la herramienta, mejor rendimiento obtendrá. Y la mayoría de los benchmarks no prueban las funciones adicionales proporcionadas por la herramienta.
Cuanto más simple sea el problema resuelto por la herramienta, mejor rendimiento tendrá. Y la mayoría de los benchmarks no prueban las funcionalidades adicionales proporcionadas por la herramienta.
La jerarquía sería:
La jerarquía es como:
* **Uvicorn**: como servidor ASGI
* **Uvicorn**: un servidor ASGI
* **Starlette**: (usa Uvicorn) un microframework web
* **FastAPI**: (usa Starlette) un microframework API con varias características adicionales para construir APIs, con validación de datos, etc.
* **FastAPI**: (usa Starlette) un microframework para APIs con varias funcionalidades adicionales para construir APIs, con validación de datos, etc.
* **Uvicorn**:
* Tendrá el mejor rendimiento, ya que no tiene mucho código extra aparte del propio servidor.
* No escribirías una aplicación directamente en Uvicorn. Eso significaría que tu código tendría que incluir más o menos, al menos, todo el código proporcionado por Starlette (o **FastAPI**). Y si hicieras eso, tu aplicación final tendría la misma sobrecarga que si hubieras usado un framework y minimizado el código de tu aplicación y los errores.
* Si estás comparando Uvicorn, compáralo con los servidores de aplicaciones Daphne, Hypercorn, uWSGI, etc.
* No escribirías una aplicación directamente en Uvicorn. Eso significaría que tu código tendría que incluir, más o menos, al menos, todo el código proporcionado por Starlette (o **FastAPI**). Y si hicieras eso, tu aplicación final tendría la misma carga que si hubieras usado un framework, minimizando el código de tu aplicación y los bugs.
* Si estás comparando Uvicorn, compáralo con Daphne, Hypercorn, uWSGI, etc. Servidores de aplicaciones.
* **Starlette**:
* Tendrá el siguiente mejor desempeño, después de Uvicorn. De hecho, Starlette usa Uvicorn para correr. Por lo tanto, probablemente sólo pueda volverse "más lento" que Uvicorn al tener que ejecutar más código.
* Pero te proporciona las herramientas para crear aplicaciones web simples, con <abbrtitle="también conocido en español como: enrutamiento">routing</abbr> basado en <abbrtitle="tambien conocido en español como: rutas">paths</abbr>, etc.
* Tendrá el siguiente mejor rendimiento, después de Uvicorn. De hecho, Starlette usa Uvicorn para ejecutarse. Así que probablemente solo pueda ser "más lento" que Uvicorn por tener que ejecutar más código.
* Pero te proporciona las herramientas para construir aplicaciones web sencillas, con enrutamiento basado en paths, etc.
* Si estás comparando Starlette, compáralo con Sanic, Flask, Django, etc. Frameworks web (o microframeworks).
* **FastAPI**:
* De la misma manera que Starlette usa Uvicorn y no puede ser más rápido que él, **FastAPI** usa Starlette, por lo que no puede ser más rápido que él.
* * FastAPI ofrece más características además de las de Starlette. Funciones que casi siempre necesitas al crear una API, como validación y serialización de datos. Y al usarlo, obtienes documentación automática de forma gratuita (la documentación automática ni siquiera agrega gastos generales a las aplicaciones en ejecución, se genera al iniciar).
* Si no usaras FastAPI y usaras Starlette directamente (u otra herramienta, como Sanic, Flask, Responder, etc.), tendrías que implementar toda la validación y serialización de datos tu mismo. Por lo tanto, tu aplicación final seguirá teniendo la misma sobrecarga que si se hubiera creado con FastAPI. Y en muchos casos, esta validación y serialización de datos constituye la mayor cantidad de código escrito en las aplicaciones.
* Entonces, al usar FastAPI estás ahorrando tiempo de desarrollo, errores, líneas de código y probablemente obtendrías el mismo rendimiento (o mejor) que obtendrías si no lo usaras (ya que tendrías que implementarlo todo en tu código).
* Si estás comparando FastAPI, compáralo con un framework de aplicaciones web (o conjunto de herramientas) que proporciona validación, serialización y documentación de datos, como Flask-apispec, NestJS, Molten, etc. Frameworks con validación, serialización y documentación automáticas integradas.
* De la misma forma en que Starlette usa Uvicorn y no puede ser más rápido que él, **FastAPI** usa Starlette, por lo que no puede ser más rápido que él.
* FastAPI ofrece más funcionalidades además de las de Starlette. Funcionalidades que casi siempre necesitas al construir APIs, como la validación y serialización de datos. Y al utilizarlo, obtienes documentación automática gratis (la documentación automática ni siquiera añade carga a las aplicaciones en ejecución, se genera al inicio).
* Si no usabas FastAPI y utilizabas Starlette directamente (u otra herramienta, como Sanic, Flask, Responder, etc.) tendrías que implementar toda la validación y serialización de datos por ti mismo. Entonces, tu aplicación final aún tendría la misma carga que si hubiera sido construida usando FastAPI. Y en muchos casos, esta validación y serialización de datos es la mayor cantidad de código escrito en las aplicaciones.
* Entonces, al usar FastAPI estás ahorrando tiempo de desarrollo, bugs, líneas de código, y probablemente obtendrías el mismo rendimiento (o mejor) que si no lo usaras (ya que tendrías que implementarlo todo en tu código).
* Si estás comparando FastAPI, compáralo con un framework de aplicación web (o conjunto de herramientas) que proporcione validación de datos, serialización y documentación, como Flask-apispec, NestJS, Molten, etc. Frameworks con validación de datos, serialización y documentación automáticas integradas.
Desplegar una aplicación hecha con **FastAPI** es relativamente fácil.
Desplegar una aplicación **FastAPI** es relativamente fácil.
## ¿Qué significa desplegar una aplicación?
## Qué Significa Despliegue
**Desplegar** una aplicación significa realizar una serie de pasos para hacerla **disponible para los usuarios**.
**Desplegar** una aplicación significa realizar los pasos necesarios para hacerla **disponible para los usuarios**.
Para una **API web**, normalmente implica ponerla en una **máquina remota**, con un **programa de servidor** que proporcione un buen rendimiento, estabilidad, etc, para que sus **usuarios** puedan **acceder** a la aplicación de manera eficiente y sin interrupciones o problemas.
Para una **API web**, normalmente implica ponerla en una **máquina remota**, con un **programa de servidor** que proporcione buen rendimiento, estabilidad, etc., para que tus **usuarios** puedan **acceder** a la aplicación de manera eficiente y sin interrupciones o problemas.
Esto difiere en las fases de **desarrollo**, donde estás constantemente cambiando el código, rompiéndolo y arreglándolo, deteniendo y reiniciando el servidor de desarrollo, etc.
Esto contrasta con las etapas de **desarrollo**, donde estás constantemente cambiando el código, rompiéndolo y arreglándolo, deteniendo y reiniciando el servidor de desarrollo, etc.
## Estrategias de despliegue
## Estrategias de Despliegue
Existen varias formas de hacerlo dependiendo de tu caso de uso específico y las herramientas que uses.
Hay varias maneras de hacerlo dependiendo de tu caso de uso específico y las herramientas que utilices.
Puedes **desplegar un servidor** tú mismo usando un conjunto de herramientas, puedes usar **servicios en la nube** que haga parte del trabajo por ti, o usar otras posibles opciones.
Podrías **desplegar un servidor** tú mismo utilizando una combinación de herramientas, podrías usar un **servicio en la nube** que hace parte del trabajo por ti, u otras opciones posibles.
Te enseñaré algunos de los conceptos principales que debes tener en cuenta al desplegar aplicaciones hechas con **FastAPI** (aunque la mayoría de estos conceptos aplicanpara cualquier otro tipo de aplicación web).
Te mostraré algunos de los conceptos principales que probablemente deberías tener en cuenta al desplegar una aplicación **FastAPI** (aunque la mayoría se aplica a cualquier otro tipo de aplicación web).
Podrás ver más detalles para tener en cuenta y algunas de las técnicas para hacerlo en las próximas secciones.✨
Verás más detalles a tener en cuenta y algunas de las técnicas para hacerlo en las siguientes secciones. ✨
**FastAPI** está siendo utilizado en producción en muchas aplicaciones y sistemas. La cobertura de los tests se mantiene al 100%. Sin embargo, su desarrollo sigue siendo rápido.
**FastAPI** ya se está utilizando en producción en muchas aplicaciones y sistemas. Y la cobertura de tests se mantiene al 100%. Pero su desarrollo sigue avanzando rápidamente.
Se agregan nuevas características frecuentemente, se corrigen errores continuamente y el código está constantemente mejorando.
Se añaden nuevas funcionalidades con frecuencia, se corrigen bugs regularmente, y el código sigue mejorando continuamente.
Por eso las versiones actuales siguen siendo `0.x.x`, esto significa que cada versión puede potencialmente tener <abbrtitle="cambios que rompen funcionalidades o compatibilidad">*breaking changes*</abbr>. Las versiones siguen las convenciones de <ahref="https://semver.org/"class="external-link"target="_blank"><abbrtitle="versionado semántico">*Semantic Versioning*</abbr></a>.
Por eso las versiones actuales siguen siendo `0.x.x`, esto refleja que cada versión podría tener potencialmente cambios incompatibles. Esto sigue las convenciones de <ahref="https://semver.org/"class="external-link"target="_blank">Semantic Versioning</a>.
Puedes crear aplicaciones listas para producción con **FastAPI** ahora mismo (y probablemente lo has estado haciendo por algún tiempo), solo tienes que asegurarte de usar la versión que funciona correctamente con el resto de tu código.
Puedes crear aplicaciones de producción con **FastAPI** ahora mismo (y probablemente ya lo has estado haciendo desde hace algún tiempo), solo debes asegurarte de que utilizas una versión que funciona correctamente con el resto de tu código.
## Fijar la versión de `fastapi`
## Fijar tu versión de `fastapi`
Lo primero que debes hacer en tu proyecto es "fijar" la última versión específica de **FastAPI** que sabes que funciona bien con tu aplicación.
Lo primero que debes hacer es "fijar" la versión de **FastAPI** que estás usando a la versión específica más reciente que sabes que funciona correctamente para tu aplicación.
Por ejemplo, digamos que estás usando la versión `0.45.0` en tu aplicación.
Por ejemplo, digamos que estás utilizando la versión `0.112.0` en tu aplicación.
Si usas el archivo `requirements.txt` puedes especificar la versión con:
Si usas un archivo `requirements.txt` podrías especificar la versión con:
```txt
fastapi==0.45.0
fastapi[standard]==0.112.0
```
esto significa que usarás específicamente la versión `0.45.0`.
eso significaría que usarías exactamente la versión `0.112.0`.
También puedes fijar las versiones de esta forma:
O también podrías fijarla con:
```txt
fastapi>=0.45.0,<0.46.0
fastapi[standard]>=0.112.0,<0.113.0
```
esto significa que usarás la versión `0.45.0` o superiores, pero menores a la versión `0.46.0`, por ejemplo, la versión `0.45.2` sería aceptada.
eso significaría que usarías las versiones `0.112.0` o superiores, pero menores que `0.113.0`, por ejemplo, una versión `0.112.2` todavía sería aceptada.
Si usas cualquier otra herramienta para manejar tus instalaciones, como Poetry, Pipenv, u otras, todas tienen una forma que puedes usar para definir versiones específicas para tus paquetes.
Si utilizas cualquier otra herramienta para gestionar tus instalaciones, como `uv`, Poetry, Pipenv, u otras, todas tienen una forma que puedes usar para definir versiones específicas para tus paquetes.
## Versiones disponibles
Puedes ver las versiones disponibles (por ejemplo, para revisar cuál es la actual) en las [Release Notes](../release-notes.md){.internal-link target=_blank}.
Puedes ver las versiones disponibles (por ejemplo, para revisar cuál es la más reciente) en las [Release Notes](../release-notes.md){.internal-link target=_blank}.
## Acerca de las versiones
## Sobre las versiones
Siguiendo las convenciones de*Semantic Versioning*, cualquier versión por debajo de `1.0.0` puede potencialmente tener <abbrtitle="cambios que rompen funcionalidades o compatibilidad">*breaking changes*</abbr>.
Siguiendo las convenciones del Semantic Versioning, cualquier versión por debajo de `1.0.0` podría potencialmente añadir cambios incompatibles.
FastAPI también sigue la convención de que cualquier cambio hecho en una <abbrtitle="versiones de parche">"PATCH" version</abbr> es para solucionar errores y <abbrtitle="cambios que no rompan funcionalidades o compatibilidad">*non-breaking changes*</abbr>.
FastAPI también sigue la convención de que cualquier cambio de versión "PATCH" es para corrección de bugs y cambios no incompatibles.
/// tip | Consejo
El <abbrtitle="parche">"PATCH"</abbr> es el último número, por ejemplo, en `0.2.3`, la <abbrtitle="versiones de parche">PATCH version</abbr> es `3`.
El "PATCH" es el último número, por ejemplo, en `0.2.3`, la versión PATCH es `3`.
///
Entonces, deberías fijar la versión así:
Así que deberías poder fijar a una versión como:
```txt
fastapi>=0.45.0,<0.46.0
```
En versiones <abbrtitle="versiones menores">"MINOR"</abbr> son añadidas nuevas características y posibles <abbrtitle="Cambios que rompen posibles funcionalidades o compatibilidad">breaking changes</abbr>.
Los cambios incompatibles y nuevas funcionalidades se añaden en versiones "MINOR".
/// tip | Consejo
La versión "MINOR" es el número en el medio, por ejemplo, en `0.2.3`, la <abbrtitle="versión menor">"MINOR" version</abbr> es `2`.
El "MINOR" es el número en el medio, por ejemplo, en `0.2.3`, la versión MINOR es `2`.
///
## Actualizando las versiones de FastAPI
Para esto es recomendable primero añadir tests a tu aplicación.
Deberías añadir tests para tu aplicación.
Con **FastAPI** es muy fácil (gracias a Starlette), revisa la documentación [Testing](../tutorial/testing.md){.internal-link target=_blank}
Con **FastAPI** es muy fácil (gracias a Starlette), revisa la documentación: [Testing](../tutorial/testing.md){.internal-link target=_blank}
Luego de tener los tests, puedes actualizar la versión de **FastAPI** a una más reciente y asegurarte de que tu código funciona correctamente ejecutando los tests.
Después de tener tests, puedes actualizar la versión de **FastAPI** a una más reciente, y asegurarte de que todo tu código está funcionando correctamente ejecutando tus tests.
Si todo funciona correctamente, o haces los cambios necesarios para que esto suceda, y todos tus tests pasan, entonces puedes fijar tu versión de `fastapi` a la más reciente.
Si todo está funcionando, o después de hacer los cambios necesarios, y todos tus tests pasan, entonces puedes fijar tu `fastapi` a esa nueva versión más reciente.
## Acerca de Starlette
## Sobre Starlette
No deberías fijar la versión de `starlette`.
Diferentes versiones de **FastAPI**pueden usar una versión específica de Starlette.
Diferentes versiones de **FastAPI**utilizarán una versión más reciente específica de Starlette.
Entonces, puedes dejar que **FastAPI** se asegure por sí mismo de qué versión de Starlette usar.
Así que, puedes simplemente dejar que **FastAPI** use la versión correcta de Starlette.
## Acerca de Pydantic
## Sobre Pydantic
Pydantic incluye los tests para **FastAPI**dentro de sus propios tests, esto significa que las versiones de Pydantic (superiores a `1.0.0`) son compatibles con FastAPI.
Pydantic incluye los tests para **FastAPI**con sus propios tests, así que nuevas versiones de Pydantic (por encima de `1.0.0`) siempre son compatibles con FastAPI.
Puedes fijar Pydantic a cualquier versión superior a `1.0.0` e inferior a `2.0.0` que funcione para ti.
Puedes fijar Pydantic a cualquier versión por encima de `1.0.0` que funcione para ti.
* <ahref="https://github.com/OAI/OpenAPI-Specification"class="external-link"target="_blank"><strong>OpenAPI</strong></a> para la creación de APIs, incluyendo declaraciones de <abbrtitle="en español: ruta. En inglés también conocido cómo: endpoints, routes">path</abbr><abbrtitle="también conocido como HTTP methods, cómo POST, GET, PUT, DELETE">operations</abbr>, parámetros, <abbrtitle="cuerpo del mensaje HTTP">body</abbr> requests, seguridad, etc.
* Documentación automática del modelo de datos con <ahref="https://json-schema.org/"class="external-link"target="_blank"><strong>JSON Schema</strong></a> (dado que OpenAPI mismo está basado en JSON Schema).
* Diseñado alrededor de estos estándares después de un estudio meticuloso. En vez de ser una capa añadida a último momento.
* Esto también permite la **generación automática de código de cliente** para muchos lenguajes.
* <ahref="https://github.com/OAI/OpenAPI-Specification"class="external-link"target="_blank"><strong>OpenAPI</strong></a> para la creación de APIs, incluyendo declaraciones de <abbrtitle="también conocido como: endpoints, rutas">path</abbr><abbrtitle="también conocido como métodos HTTP, como POST, GET, PUT, DELETE">operations</abbr>, parámetros, request bodies, seguridad, etc.
* Documentación automática de modelos de datos con <ahref="https://json-schema.org/"class="external-link"target="_blank"><strong>JSON Schema</strong></a> (ya que OpenAPI en sí mismo está basado en JSON Schema).
* Diseñado alrededor de estos estándares, tras un estudio meticuloso. En lugar de ser una capa adicional.
* Esto también permite el uso de **generación de código cliente automática** en muchos idiomas.
### Documentación automática
Documentación interactiva de la API e interfaces web de exploración. Hay múltiples opciones, dos incluidas por defecto, porque el framework está basado en OpenAPI.
Interfaces web de documentación y exploración de APIs interactivas. Como el framework está basado en OpenAPI, hay múltiples opciones, 2 incluidas por defecto.
* <ahref="https://github.com/swagger-api/swagger-ui"class="external-link"target="_blank"><strong>Swagger UI</strong></a>, con exploración interactiva, llama y prueba tu API directamente desde tu navegador.
* <ahref="https://github.com/swagger-api/swagger-ui"class="external-link"target="_blank"><strong>Swagger UI</strong></a>, con exploración interactiva, llama y prueba tu API directamente desde el navegador.
Todo está basado en las declaraciones de tipo de **Python 3.8** estándar (gracias a Pydantic). No necesitas aprender una sintaxis nueva, solo Python moderno.
Todo está basado en declaraciones estándar de **tipos en Python** (gracias a Pydantic). Sin nueva sintaxis que aprender. Solo Python moderno estándar.
Si necesitas un repaso de 2 minutos de cómo usar los tipos de Python (así no uses FastAPI) prueba el tutorial corto: [Python Types](python-types.md){.internal-link target=_blank}.
Si necesitas un repaso de 2 minutos sobre cómo usar tipos en Python (aunque no uses FastAPI), revisa el tutorial corto: [Tipos en Python](python-types.md){.internal-link target=_blank}.
Escribes Python estándar con tipos así:
Escribes Python estándar con tipos:
```Python
from datetime import date
from pydantic import BaseModel
# Declaras la variable como un str
# y obtienes soporte del editor dentro de la función
# Declara una variable como un str
# y obtiene soporte del editor dentro de la función
def main(user_id: str):
return user_id
@ -49,7 +49,7 @@ class User(BaseModel):
joined: date
```
Este puede ser usado como:
Que luego puede ser usado como:
```Python
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
@ -67,135 +67,135 @@ my_second_user: User = User(**second_user_data)
`**second_user_data` significa:
Pasa las <abbrtitle="en español key se refiere a la guía de un diccionario">keys</abbr> y los valores del dict `second_user_data` directamente como argumentos de key-value, equivalente a: `User(id=4, name="Mary", joined="2018-11-30")`
Pasa las claves y valores del dict `second_user_data` directamente como argumentos de clave-valor, equivalente a: `User(id=4, name="Mary", joined="2018-11-30")`
///
### Soporte del editor
El framework fue diseñado en su totalidad para ser fácil e intuitivo de usar. Todas las decisiones fueron probadas en múltiples editores antes de comenzar el desarrollo para asegurar la mejor experiencia de desarrollo.
Todo el framework fue diseñado para ser fácil e intuitivo de usar, todas las decisiones fueron probadas en múltiples editores incluso antes de comenzar el desarrollo, para asegurar la mejor experiencia de desarrollo.
En la última encuesta a desarrolladores de Python fue claro que<ahref="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features"class="external-link"target="_blank">la característica más usada es el "auto-completado"</a>.
En las encuestas a desarrolladores de Python, es claro<ahref="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features"class="external-link"target="_blank">que una de las funcionalidades más usadas es el "autocompletado"</a>.
El framework **FastAPI** está creado para satisfacer eso. El auto-completado funciona en todas partes.
Todo el framework **FastAPI** está basado para satisfacer eso. El autocompletado funciona en todas partes.
No vas a tener que volver a la documentación seguido.
Rara vez necesitarás regresar a la documentación.
Así es como tu editor te puede ayudar:
Aquí está cómo tu editor podría ayudarte:
* en <ahref="https://code.visualstudio.com/"class="external-link"target="_blank">Visual Studio Code</a>:

Obtendrás completado para tu código que podrías haber considerado imposible antes. Por ejemplo, el key `price` dentro del JSON body (que podría haber estado anidado) que viene de un request.
Obtendrás autocompletado en código que podrías considerar imposible antes. Por ejemplo, la clave `price` dentro de un cuerpo JSON (que podría haber estado anidado) que proviene de un request.
Ya no pasará que escribas los nombres de key equivocados, o que tengas que revisar constantemente la documentación o desplazarte arriba y abajo para saber si usaste `username` o `user_name`.
No más escribir nombres de claves incorrectos, yendo de un lado a otro entre la documentación, o desplazándote hacia arriba y abajo para encontrar si finalmente usaste `username` o `user_name`.
### Corto
### Breve
Tiene **configuraciones por defecto** razonables para todo, con configuraciones opcionales en todas partes. Todos los parámetros pueden ser ajustados para tus necesidades y las de tu API.
Tiene **valores predeterminados** sensatos para todo, con configuraciones opcionales en todas partes. Todos los parámetros se pueden ajustar finamente para hacer lo que necesitas y para definir el API que necesitas.
Pero, todo **simplemente funciona** por defecto.
Pero por defecto, todo **"simplemente funciona"**.
### Validación
* Validación para la mayoría (¿o todos?) los **tipos de datos** de Python incluyendo:
* Validación para la mayoría (¿o todas?) de los **tipos de datos** de Python, incluyendo:
* Objetos JSON (`dict`).
* JSON array (`list`) definiendo tipos de ítem.
* Campos de texto (`str`) definiendo longitudes mínimas y máximas.
* Array JSON (`list`) definiendo tipos de elementos.
* Campos de cadena de caracteres (`str`), definiendo longitudes mínimas y máximas.
* Números (`int`, `float`) con valores mínimos y máximos, etc.
* Validación para tipos más exóticos como:
* Validación para tipos más exóticos, como:
* URL.
* Email.
* UUID.
* ...y otros.
Toda la validación es manejada por **Pydantic**, que es robusto y sólidamente establecido.
Toda la validación es manejada por **Pydantic**, una herramienta bien establecida y robusta.
### Seguridad y autenticación
La seguridad y la autenticación están integradas. Sin ningún compromiso con bases de datos ni modelos de datos.
Seguridad y autenticación integradas. Sin ningún compromiso con bases de datos o modelos de datos.
Todos los schemes de seguridad están definidos en OpenAPI incluyendo:
Todos los esquemas de seguridad definidos en OpenAPI, incluyendo:
* HTTP Basic.
* **OAuth2** (también con **JWT tokens**). Prueba el tutorial en [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
* HTTP Básico.
* **OAuth2** (también con **tokens JWT**). Revisa el tutorial sobre [OAuth2 con JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
* API keys en:
* Headers.
* Parámetros de Query.
* Parámetros de query.
* Cookies, etc.
Más todas las características de seguridad de Starlette (incluyendo **session cookies**).
Además de todas las características de seguridad de Starlette (incluyendo **cookies de sesión**).
Todo ha sido construido como herramientas y componentes reutilizables que son fácilmente integrados con tus sistemas, almacenamiento de datos, bases de datos relacionales y no relacionales, etc.
Todo construido como herramientas y componentes reutilizables que son fáciles de integrar con tus sistemas, almacenes de datos, bases de datos relacionales y NoSQL, etc.
### Dependency Injection
### Inyección de dependencias
FastAPI incluye un sistema de <abbrtitle='En español: Inyección de Dependencias. También conocido en inglés cómo: "components", "resources", "services", "providers"'><strong>Dependency Injection</strong></abbr> extremadamente poderoso y fácil de usar.
FastAPI incluye un sistema de <abbrtitle='también conocido como "componentes", "recursos", "servicios", "proveedores"'><strong>Inyección de Dependencias</strong></abbr> extremadamente fácil de usar, pero extremadamente potente.
* Inclusive las dependencias pueden tener dependencias creando una jerarquía o un **"grafo" de dependencias**.
* Todas son **manejadas automáticamente** por el framework.
* Todas las dependencias pueden requerir datos de los requests y aumentar las restricciones del *path operation* y la documentación automática.
* **Validación automática** inclusive para parámetros del*path operation* definidos en las dependencias.
* Soporte para sistemas complejos de autenticación de usuarios, **conexiones con bases de datos**, etc.
* **Sin comprometerse** con bases de datos, frontend, etc. Pero permitiendo integración fácil con todos ellos.
* Incluso las dependencias pueden tener dependencias, creando una jerarquía o **"gráfico de dependencias"**.
* Todo **manejado automáticamente** por el framework.
* Todas las dependencias pueden requerir datos de los requests y **aumentar las restricciones de la path operation** y la documentación automática.
* **Validación automática** incluso para los parámetros de*path operation* definidos en las dependencias.
* Soporte para sistemas de autenticación de usuario complejos, **conexiones a bases de datos**, etc.
* **Sin compromisos** con bases de datos, frontends, etc. Pero fácil integración con todos ellos.
### "Plug-ins" ilimitados
O dicho de otra manera, no hay necesidad para "plug-ins". Importa y usa el código que necesites.
O de otra manera, no hay necesidad de ellos, importa y usa el código que necesitas.
Cualquier integración está diseñada para que sea tan sencilla de usar (con dependencias) que puedas crear un "plug-in" para tu aplicación en dos líneas de código usando la misma estructura y sintaxis que usaste para tus *path operations*.
Cualquier integración está diseñada para ser tan simple de usar (con dependencias) que puedes crear un "plug-in" para tu aplicación en 2 líneas de código usando la misma estructura y sintaxis utilizada para tus *path operations*.
### Probado
* <abbrtitle="La cantidad de código que es probado automáticamente">Cobertura de pruebas</abbr> al 100%.
* Base de código 100%<abbrtitle="Type annotations de Python, con esto tu editor y otras herramientas externas pueden darte mejor soporte">anotada con tipos</abbr>.
* 100% de <abbrtitle="La cantidad de código que se prueba automáticamente">cobertura de tests</abbr>.
* Código completamente<abbrtitle="Anotaciones de tipos en Python, con esto tu editor y herramientas externas pueden ofrecerte mejor soporte">anotado con tipos</abbr>.
* Usado en aplicaciones en producción.
## Características de Starlette
## Funcionalidades de Starlette
**FastAPI** está basado y es completamente compatible con<ahref="https://www.starlette.io/"class="external-link"target="_blank"><strong>Starlette</strong></a>. Tanto así, que cualquier código de Starlette que tengas también funcionará.
**FastAPI** es totalmente compatible con (y está basado en)<ahref="https://www.starlette.io/"class="external-link"target="_blank"><strong>Starlette</strong></a>. Así que, cualquier código adicional de Starlette que tengas, también funcionará.
`FastAPI` es realmente una sub-clase de `Starlette`. Así que, si ya conoces o usas Starlette, muchas de las características funcionarán de la misma manera.
`FastAPI` es en realidad una subclase de `Starlette`. Así que, si ya conoces o usas Starlette, la mayoría de las funcionalidades funcionarán de la misma manera.
Con **FastAPI** obtienes todas las características de **Starlette** (porque FastAPI es simplemente Starlette en esteroides):
Con **FastAPI** obtienes todas las funcionalidades de **Starlette** (ya que FastAPI es simplemente Starlette potenciado):
* Desempeño realmente impresionante. Es uno<ahref="https://github.com/encode/starlette#performance"class="external-link"target="_blank"> de los frameworks de Python más rápidos, a la par con**NodeJS** y **Go**</a>.
* Rendimiento seriamente impresionante. Es<ahref="https://github.com/encode/starlette#performance"class="external-link"target="_blank">uno de los frameworks de Python más rápidos disponibles, a la par de**NodeJS** y **Go**</a>.
* Soporte para **WebSocket**.
* <abbrtitle="En español: tareas que se ejecutan en el fondo, sin frenar requests, en el mismo proceso. En ingles: In-process background tasks">Tareas en background</abbr>.
* **CORS**, GZip, archivos estáticos, responses en streaming.
* Soporte para **Session y Cookie**.
* Cobertura de tests del 100%.
* Código completamente anotado con tipos.
## Características de Pydantic
## Funcionalidades de Pydantic
**FastAPI** está basado y es completamente compatible con<ahref="https://docs.pydantic.dev/"class="external-link"target="_blank"><strong>Pydantic</strong></a>. Tanto así, que cualquier código de Pydantic que tengas también funcionará.
**FastAPI** es totalmente compatible con (y está basado en)<ahref="https://docs.pydantic.dev/"class="external-link"target="_blank"><strong>Pydantic</strong></a>. Por lo tanto, cualquier código adicional de Pydantic que tengas, también funcionará.
Esto incluye a librerías externas basadas en Pydantic como <abbrtitle="Object-Relational Mapper">ORM</abbr>s y<abbrtitle="Object-Document Mapper">ODM</abbr>s para bases de datos.
Incluyendo paquetes externos también basados en Pydantic, como <abbrtitle="Object-Relational Mapper">ORM</abbr>s,<abbrtitle="Object-Document Mapper">ODM</abbr>s para bases de datos.
Esto también significa que en muchos casos puedes pasar el mismo objeto que obtuviste de un request **directamente a la base de datos**, dado que todo es validado automáticamente.
Esto también significa que, en muchos casos, puedes pasar el mismo objeto que obtienes de un request **directamente a la base de datos**, ya que todo se valida automáticamente.
Lo mismo aplica para el sentido contrario. En muchos casos puedes pasar el objeto que obtienes de la base de datos **directamente al cliente**.
Lo mismo aplica al revés, en muchos casos puedes simplemente pasar el objeto que obtienes de la base de datos **directamente al cliente**.
Con **FastAPI** obtienes todas las características de **Pydantic** (dado que FastAPI está basado en Pydantic para todo el manejo de datos):
Con **FastAPI** obtienes todas las funcionalidades de **Pydantic** (ya que FastAPI está basado en Pydantic para todo el manejo de datos):
* **Sin dificultades para entender**:
* No necesitas aprender un nuevo micro-lenguaje de definición de schemas.
* Si sabes tipos de Python, sabes cómo usar Pydantic.
* Interactúa bien con tu **<abbrtitle="en inglés: Integrated Development Environment, similar a editor de código">IDE</abbr>/<abbrtitle="Un programa que chequea errores en el código">linter</abbr>/cerebro**:
* Porque las estructuras de datos de Pydantic son solo <abbrtitle='En español: ejemplares. Aunque a veces los llaman incorrectamente "instancias"'>instances</abbr> de clases que tu defines, el auto-completado, el linting, mypy y tu intuición deberían funcionar bien con tus datos validados.
* **Sin complicaciones**:
* Sin micro-lenguaje de definición de esquemas nuevo que aprender.
* Si conoces los tipos en Python sabes cómo usar Pydantic.
* Se lleva bien con tu **<abbrtitle="Entorno de Desarrollo Integrado, similar a un editor de código">IDE</abbr>/<abbrtitle="Un programa que verifica errores de código">linter</abbr>/cerebro**:
* Porque las estructuras de datos de pydantic son solo instances de clases que defines; autocompletado, linting, mypy y tu intuición deberían funcionar correctamente con tus datos validados.
* Valida **estructuras complejas**:
* Usa modelos jerárquicos de modelos de Pydantic, `typing` de Python, `List` y `Dict`, etc.
* Los validadores también permiten que se definan fácil y claramente schemas complejos de datos. Estos son chequeados y documentados como JSON Schema.
* Puedes tener objetos de **JSON profundamente anidados** y que todos sean validados y anotados.
* Uso de modelos jerárquicos de Pydantic, `List` y `Dict` de `typing` de Python, etc.
* Y los validadores permiten definir, verificar y documentar de manera clara y fácil esquemas de datos complejos como JSON Schema.
* Puedes tener objetos JSON profundamente **anidados** y validarlos todos y anotarlos.
* **Extensible**:
* Pydantic permite que se definan tipos de datos a la medida o puedes extender la validación con métodos en un modelo decorado con el <abbrtitle="en inglés: validator decorator"> decorador de validación</abbr>.
* Cobertura de pruebas al 100%.
* Pydantic permite definir tipos de datos personalizados o puedes extender la validación con métodos en un modelo decorados con el decorador validator.
* Con <ahref="https://tartiflette.github.io/tartiflette-asgi/"class="external-link"target="_blank">Tartiflette ASGI</a> para proveer integración con ASGI
* Con <ahref="https://tartiflette.github.io/tartiflette-asgi/"class="external-link"target="_blank">Tartiflette ASGI</a> para proporcionar integración con ASGI
* Con <ahref="https://github.com/ciscorn/starlette-graphene3"class="external-link"target="_blank">starlette-graphene3</a>
## GraphQL con Strawberry
Si necesitas o quieres trabajar con **GraphQL**, <ahref="https://strawberry.rocks/"class="external-link"target="_blank">**Strawberry**</a> es la library **recomendada** por el diseño más cercano a **FastAPI**, el cual es completamente basado en **anotaciones de tipo**.
Si necesitas o quieres trabajar con **GraphQL**, <ahref="https://strawberry.rocks/"class="external-link"target="_blank">**Strawberry**</a> es el paquete **recomendado** ya que tiene un diseño muy similar al diseño de **FastAPI**, todo basado en **anotaciones de tipos**.
Dependiendo de tus casos de uso, podrías preferir usar una library diferente, pero si me preguntas, probablemente te recomendaría**Strawberry**.
Dependiendo de tu caso de uso, podrías preferir usar un paquete diferente, pero si me preguntas, probablemente te sugeriría probar**Strawberry**.
Aquí hay una pequeña muestra de cómo podrías integrar Strawberry con FastAPI:
Aquí tienes una pequeña vista previa de cómo podrías integrar Strawberry con FastAPI:
Puedes aprender más sobre Strawberry en la <ahref="https://strawberry.rocks/"class="external-link"target="_blank">documentación de Strawberry</a>.
Y también en la documentación sobre <ahref="https://strawberry.rocks/docs/integrations/fastapi"class="external-link"target="_blank">Strawberry con FastAPI</a>.
Y también la documentación sobre <ahref="https://strawberry.rocks/docs/integrations/fastapi"class="external-link"target="_blank">Strawberry con FastAPI</a>.
## Clase obsoleta `GraphQLApp` en Starlette
## `GraphQLApp` viejo de Starlette
Versiones anteriores de Starlette incluyen la clase `GraphQLApp` para integrarlo con <ahref="https://graphene-python.org/"class="external-link"target="_blank">Graphene</a>.
Las versiones anteriores de Starlette incluían una clase `GraphQLApp` para integrar con <ahref="https://graphene-python.org/"class="external-link"target="_blank">Graphene</a>.
Esto fue marcado como obsoleto en Starlette, pero si aún tienes código que lo usa, puedes fácilmente **migrar** a <ahref="https://github.com/ciscorn/starlette-graphene3"class="external-link"target="_blank">starlette-graphene3</a>, la cual cubre el mismo caso de uso y tiene una **interfaz casi idéntica.**
Fue deprecada de Starlette, pero si tienes código que lo usaba, puedes fácilmente **migrar** a <ahref="https://github.com/ciscorn/starlette-graphene3"class="external-link"target="_blank">starlette-graphene3</a>, que cubre el mismo caso de uso y tiene una **interfaz casi idéntica**.
/// tip | Consejo
Si necesitas GraphQL, te recomendaría revisar <ahref="https://strawberry.rocks/"class="external-link"target="_blank">Strawberry</a>, que es basada en anotaciones de tipo en vez de clases y tipos personalizados.
Si necesitas GraphQL, aún te recomendaría revisar <ahref="https://strawberry.rocks/"class="external-link"target="_blank">Strawberry</a>, ya que se basa en anotaciones de tipos en lugar de clases y tipos personalizados.
///
## Aprende más
## Aprende Más
Puedes aprender más acerca de **GraphQL** en la <ahref="https://graphql.org/"class="external-link"target="_blank">documentación oficial de GraphQL</a>.
Puedes aprender más sobre **GraphQL** en la <ahref="https://graphql.org/"class="external-link"target="_blank">documentación oficial de GraphQL</a>.
También puedes leer más acerca de cada library descrita anteriormente en sus enlaces.
También puedes leer más sobre cada uno de esos paquetes descritos arriba en sus enlaces.
FastAPI es un web framework moderno y rápido (de alto rendimiento) para construir APIs con Python basado en las anotaciones de tipos estándar de Python.
Sus características principales son:
FastAPI es un framework web moderno, rápido (de alto rendimiento), para construir APIs con Python basado en las anotaciones de tipos estándar de Python.
* **Rapidez**: Alto rendimiento, a la par con **NodeJS** y **Go** (gracias a Starlette y Pydantic). [Uno de los frameworks de Python más rápidos](#rendimiento).
Las características clave son:
* **Rápido de programar**: Incrementa la velocidad de desarrollo entre 200% y 300%. *
* **Menos errores**: Reduce los errores humanos (de programador) aproximadamente un 40%. *
* **Intuitivo**: Gran soporte en los editores con <abbrtitle="conocido en inglés como auto-complete, autocompletion, IntelliSense, completion">auto completado</abbr> en todas partes. Gasta menos tiempo <abbrtitle="buscando y corrigiendo errores">debugging</abbr>.
* **Fácil**: Está diseñado para ser fácil de usar y aprender. Gastando menos tiempo leyendo documentación.
* **Corto**: Minimiza la duplicación de código. Múltiples funcionalidades con cada declaración de parámetros. Menos errores.
* **Robusto**: Crea código listo para producción con documentación automática interactiva.
* **Basado en estándares**: Basado y totalmente compatible con los estándares abiertos para APIs: <ahref="https://github.com/OAI/OpenAPI-Specification"class="external-link"target="_blank">OpenAPI</a> (conocido previamente como Swagger) y <ahref="https://json-schema.org/"class="external-link"target="_blank">JSON Schema</a>.
* **Rápido**: Muy alto rendimiento, a la par con **NodeJS** y **Go** (gracias a Starlette y Pydantic). [Uno de los frameworks Python más rápidos disponibles](#performance).
* **Rápido de programar**: Aumenta la velocidad para desarrollar funcionalidades en aproximadamente un 200% a 300%. *
* **Menos bugs**: Reduce en aproximadamente un 40% los errores inducidos por humanos (desarrolladores). *
* **Intuitivo**: Gran soporte para editores. <abbrtitle="también conocido como autocompletado, IntelliSense">Autocompletado</abbr> en todas partes. Menos tiempo depurando.
* **Fácil**: Diseñado para ser fácil de usar y aprender. Menos tiempo leyendo documentación.
* **Corto**: Minimiza la duplicación de código. Múltiples funcionalidades desde cada declaración de parámetro. Menos bugs.
* **Robusto**: Obtén código listo para producción. Con documentación interactiva automática.
* **Basado en estándares**: Basado (y completamente compatible) con los estándares abiertos para APIs: <ahref="https://github.com/OAI/OpenAPI-Specification"class="external-link"target="_blank">OpenAPI</a> (anteriormente conocido como Swagger) y <ahref="https://json-schema.org/"class="external-link"target="_blank">JSON Schema</a>.
<small>* Esta estimación está basada en pruebas con un equipo de desarrollo interno construyendo aplicaciones listas para producción.</small>
<small>* estimación basada en pruebas con un equipo de desarrollo interno, construyendo aplicaciones de producción.</small>
## Sponsors
@ -64,41 +67,47 @@ Sus características principales son:
## Opiniones
"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
"_[...] Estoy usando **FastAPI** un montón estos días. [...] De hecho, estoy planeando usarlo para todos los servicios de **ML de mi equipo en Microsoft**. Algunos de ellos se están integrando en el núcleo del producto **Windows** y algunos productos de **Office**._"
"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
"_Adoptamos el paquete **FastAPI** para crear un servidor **REST** que pueda ser consultado para obtener **predicciones**. [para Ludwig]_"
<divstyle="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong><ahref="https://eng.uber.com/ludwig-v0-2/"target="_blank"><small>(ref)</small></a></div>
<divstyle="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, y Sai Sumanth Miryala - <strong>Uber</strong><ahref="https://eng.uber.com/ludwig-v0-2/"target="_blank"><small>(ref)</small></a></div>
---
"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with**FastAPI**]_"
"_**Netflix** se complace en anunciar el lanzamiento de código abierto de nuestro framework de orquestación de **gestión de crisis**: **Dispatch**! [construido con**FastAPI**]_"
"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
"_Honestamente, lo que has construido parece súper sólido y pulido. En muchos aspectos, es lo que quería que **Hug** fuera; es realmente inspirador ver a alguien construir eso._"
<divstyle="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><ahref="https://github.com/hugapi/hug"target="_blank">creador de Hug</a></strong><ahref="https://news.ycombinator.com/item?id=19455465"target="_blank"><small>(ref)</small></a></div>
---
"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_"
"_Si estás buscando aprender un **framework moderno** para construir APIs REST, échale un vistazo a **FastAPI** [...] Es rápido, fácil de usar y fácil de aprender [...]_"
"_Nos hemos cambiado a **FastAPI** para nuestras **APIs** [...] Creo que te gustará [...]_"
<divstyle="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><ahref="https://explosion.ai"target="_blank">fundadores de Explosion AI</a> - <ahref="https://spacy.io"target="_blank">creadores de spaCy</a></strong><ahref="https://twitter.com/_inesmontani/status/1144173225322143744"target="_blank"><small>(ref)</small></a> - <ahref="https://twitter.com/honnibal/status/1144031421859655680"target="_blank"><small>(ref)</small></a></div>
---
"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_"
"_Si alguien está buscando construir una API de Python para producción, altamente recomendaría **FastAPI**. Está **hermosamente diseñado**, es **simple de usar** y **altamente escalable**, se ha convertido en un **componente clave** en nuestra estrategia de desarrollo API primero y está impulsando muchas automatizaciones y servicios como nuestro Ingeniero Virtual TAC._"
Si estás construyendo un app de <abbrtitle="Interfaz de línea de comandos en español">CLI</abbr> para ser usada en la terminal en vez de una API web, fíjate en<ahref="https://typer.tiangolo.com/"class="external-link"target="_blank">**Typer**</a>.
Si estás construyendo una aplicación de <abbrtitle="Interfaz de Línea de Comandos">CLI</abbr> para ser usada en el terminal en lugar de una API web, revisa<ahref="https://typer.tiangolo.com/"class="external-link"target="_blank">**Typer**</a>.
**Typer** es el hermano menor de FastAPI. La intención es que sea el **FastAPI de las CLIs**. ⌨️ 🚀
**Typer** es el hermano pequeño de FastAPI. Y está destinado a ser el **FastAPI de las CLIs**. ⌨️ 🚀
## Requisitos
FastAPI está sobre los hombros de gigantes:
FastAPI se apoya en hombros de gigantes:
* <ahref="https://www.starlette.io/"class="external-link"target="_blank">Starlette</a> para las partes web.
* <ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic</a> para las partes de datos.
## Instalación
<divclass="termy">
```console
$ pip install fastapi
---> 100%
```
</div>
También vas a necesitar un servidor ASGI para producción cómo <ahref="https://www.uvicorn.org"class="external-link"target="_blank">Uvicorn</a> o <ahref="https://github.com/pgjones/hypercorn"class="external-link"target="_blank">Hypercorn</a>.
Crea y activa un <ahref="https://fastapi.tiangolo.com/virtual-environments/"class="external-link"target="_blank">entorno virtual</a> y luego instala FastAPI:
<divclass="termy">
```console
$ pip install "uvicorn[standard]"
$ pip install "fastapi[standard]"
---> 100%
```
</div>
**Nota**: Asegúrate de poner `"fastapi[standard]"` entre comillas para asegurar que funcione en todas las terminales.
Si no lo sabes, revisa la sección _"¿Con prisa?"_ sobre <ahref="https://fastapi.tiangolo.com/es/async/#con-prisa"target="_blank">`async` y `await` en la documentación</a>.
Si no lo sabes, revisa la sección _"¿Con prisa?"_ sobre <ahref="https://fastapi.tiangolo.com/async/#in-a-hurry"target="_blank">`async` y `await` en la documentación</a>.
</details>
@ -199,11 +202,24 @@ Corre el servidor con:
<divclass="termy">
```console
$ uvicorn main:app --reload
$ fastapi dev main.py
╭────────── FastAPI CLI - Development mode ───────────╮
│ │
│ Serving at: http://127.0.0.1:8000 │
│ │
│ API docs: http://127.0.0.1:8000/docs │
│ │
│ Running in development mode, for production use: │
<summary>Sobre el comando <code>uvicorn main:app --reload</code>...</summary>
<summary>Acerca del comando <code>fastapi dev main.py</code>...</summary>
El comando `fastapi dev` lee tu archivo `main.py`, detecta la app **FastAPI** en él y arranca un servidor usando <ahref="https://www.uvicorn.org"class="external-link"target="_blank">Uvicorn</a>.
El comando `uvicorn main:app` se refiere a:
Por defecto, `fastapi dev` comenzará con auto-recarga habilitada para el desarrollo local.
* `main`: el archivo `main.py` (el"modulo" de Python).
* `app`: el objeto creado dentro de `main.py` con la línea `app = FastAPI()`.
* `--reload`: hace que el servidor se reinicie después de cambios en el código. Esta opción solo debe ser usada en desarrollo.
Puedes leer más sobre esto en la <ahref="https://fastapi.tiangolo.com/fastapi-cli/"target="_blank">documentación del CLI de FastAPI</a>.
</details>
@ -225,7 +241,7 @@ El comando `uvicorn main:app` se refiere a:
Abre tu navegador en <ahref="http://127.0.0.1:8000/items/5?q=somequery"class="external-link"target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
Verás la respuesta de JSON cómo:
Verás el response JSON como:
```JSON
{"item_id": 5, "q": "somequery"}
@ -233,37 +249,38 @@ Verás la respuesta de JSON cómo:
Ya creaste una API que:
* Recibe HTTP requests en los _paths_`/` y `/items/{item_id}`.
* Ambos _paths_ toman <em>operaciones</em>`GET` (también conocido como HTTP _methods_).
* El _path_`/items/{item_id}` tiene un _path parameter_`item_id` que debería ser un `int`.
* El _path_`/items/{item_id}` tiene un `str`_query parameter_`q` opcional.
* Recibe requests HTTP en los _paths_`/` y `/items/{item_id}`.
* Ambos _paths_ toman _operaciones_`GET` (también conocidas como métodos HTTP).
* El _path_`/items/{item_id}` tiene un _parámetro de path_`item_id` que debe ser un `int`.
* El _path_`/items/{item_id}` tiene un _parámetro de query_`q` opcional que es un `str`.
### Documentación interactiva de APIs
### Documentación interactiva de la API
Ahora ve a <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a>.
Verás la documentación automática e interactiva de la API (proveída 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 <ahref="https://github.com/swagger-api/swagger-ui"class="external-link"target="_blank">Swagger UI</a>):
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 <ahref="http://127.0.0.1:8000/redoc"class="external-link"target="_blank">http://127.0.0.1:8000/redoc</a>.
Ahora verás la documentación automática alternativa (proveída por <ahref="https://github.com/Rebilly/ReDoc"class="external-link"target="_blank">ReDoc</a>):
Verás la documentación alternativa automática (proporcionada por <ahref="https://github.com/Rebilly/ReDoc"class="external-link"target="_blank">ReDoc</a>):
* Luego haz click en el botón de "Execute". La interfaz de usuario se comunicará con tu API, enviará los parámetros y recibirá los resultados para mostrarlos en pantalla:
* Luego haz clic en el botón "Execute", la interfaz de usuario se comunicará con tu API, enviará los parámetros, obtendrá los resultados y los mostrará en la pantalla:
En resumen, declaras los tipos de parámetros, body, etc. **una vez**como parámetros de la función.
En resumen, declaras **una vez**los tipos de parámetros, body, etc. como parámetros de función.
Lo haces con tipos modernos estándar de Python.
Lo haces con tipos estándar modernos de Python.
No tienes que aprender una sintaxis nueva, los métodos o clases de una library específica, etc.
No tienes que aprender una nueva sintaxis, los métodos o clases de un paquete específico, etc.
Solo **Python** estándar.
@ -331,7 +348,7 @@ Por ejemplo, para un `int`:
item_id: int
```
o para un modelo más complejo de `Item`:
o para un modelo `Item` más complejo:
```Python
item: Item
@ -339,62 +356,62 @@ item: Item
...y con esa única declaración obtienes:
* Soporte del editor incluyendo:
* Autocompletado.
* Anotaciones de tipos.
* Soporte para editores, incluyendo:
* Autocompletado.
* Chequeo de tipos.
* Validación de datos:
* Errores automáticos y claros cuándo los datos son inválidos.
* Validación, incluso para objetos JSON profundamente anidados.
* <abbrtitle="en inglés: serialization, parsing, marshalling">Conversión</abbr> de datos de input: viniendo de la red a datos y tipos de Python. Leyendo desde:
* Errores automáticos y claros cuando los datos son inválidos.
* Validación incluso para objetos JSON profundamente anidados.
* <abbrtitle="también conocido como: serialización, parsing, marshalling">Conversión</abbr> de datos de entrada: de la red a los datos y tipos de Python. Leyendo desde:
* JSON.
* Path parameters.
* Query parameters.
* Parámetros de path.
* Parámetros de query.
* Cookies.
* Headers.
* Formularios.
* Forms.
* Archivos.
* <abbrtitle="en inglés: serialization, parsing, marshalling">Conversión</abbr> de datos de output: convirtiendo de datos y tipos de Python a datos para la red (como JSON):
* <abbrtitle="también conocido como: serialización, parsing, marshalling">Conversión</abbr> de datos de salida: convirtiendo de datos y tipos de Python a datos de red (como JSON):
Para un ejemplo más completo que incluye más características ve el <ahref="https://fastapi.tiangolo.com/tutorial/">Tutorial - Guía de Usuario</a>.
Para un ejemplo más completo incluyendo más funcionalidades, ve al <ahref="https://fastapi.tiangolo.com/tutorial/">Tutorial - Guía del Usuario</a>.
**Spoiler alert**: el Tutorial - Guía de Usuario incluye:
**Alerta de spoilers**: el tutorial - guía del usuario incluye:
* Declaración de **parámetros** en otros lugares diferentes cómo los: **headers**, **cookies**, **formularios** y **archivos**.
* Cómo agregar **requisitos de validación** cómo `maximum_length` o `regex`.
* Un sistema de **<abbrtitle="también conocido en inglés cómo: components, resources, providers, services, injectables">Dependency Injection</abbr>** poderoso y fácil de usar.
* Seguridad y autenticación incluyendo soporte para **OAuth2** con **JWT tokens** y **HTTP Basic** auth.
* Técnicas más avanzadas, pero igual de fáciles, para declarar **modelos de JSON profundamente anidados** (gracias a Pydantic).
* Muchas características extra (gracias a Starlette) como:
* Declaración de **parámetros** desde otros lugares diferentes como: **headers**, **cookies**, **campos de formulario** y **archivos**.
* Cómo establecer **restricciones de validación** como `maximum_length` o `regex`.
* Un sistema de **<abbrtitle="también conocido como componentes, recursos, proveedores, servicios, inyectables">Inyección de Dependencias</abbr>** muy poderoso y fácil de usar.
* Seguridad y autenticación, incluyendo soporte para **OAuth2** con **tokens JWT** y autenticación **HTTP Basic**.
* Técnicas más avanzadas (pero igualmente fáciles) para declarar **modelos JSON profundamente anidados** (gracias a Pydantic).
* Integración con **GraphQL** usando <ahref="https://strawberry.rocks"class="external-link"target="_blank">Strawberry</a> y otros paquetes.
* Muchas funcionalidades extra (gracias a Starlette) como:
* **WebSockets**
* **GraphQL**
* pruebas extremadamente fáciles con HTTPX y `pytest`
* pruebas extremadamente fáciles basadas en HTTPX y `pytest`
* **CORS**
* **Cookie Sessions**
* ...y mucho más.
* **Sesiones de Cookies**
* ...y más.
## Rendimiento
Benchmarks independientes de TechEmpower muestran que aplicaciones de **FastAPI** corriendo con Uvicorn cómo <ahref="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7"class="external-link"target="_blank">uno de los frameworks de Python más rápidos</a>, únicamente debajo de Starlette y Uvicorn (usados internamente por FastAPI). (*)
Benchmarks independientes de TechEmpower muestran aplicaciones **FastAPI** ejecutándose bajo Uvicorn como <ahref="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7"class="external-link"target="_blank">uno de los frameworks Python más rápidos disponibles</a>, solo por debajo de Starlette y Uvicorn (usados internamente por FastAPI). (*)
Para entender más sobre esto, ve la sección <ahref="https://fastapi.tiangolo.com/benchmarks/"class="internal-link"target="_blank">Benchmarks</a>.
Para entender más al respecto revisa la sección <ahref="https://fastapi.tiangolo.com/benchmarks/"class="internal-link"target="_blank">Benchmarks</a>.
## Dependencias
## Dependencias Opcionales
FastAPI depende de Pydantic y Starlette.
### Dependencias `standard`
Cuando instalas FastAPI con `pip install "fastapi[standard]"` viene con el grupo `standard` de dependencias opcionales:
Usadas por Pydantic:
* <ahref="https://github.com/JoshData/python-email-validator"target="_blank"><code>email-validator</code></a> - para validación de emails.
* <ahref="https://github.com/JoshData/python-email-validator"target="_blank"><code>email-validator</code></a> - para validación de correos electrónicos.
Usadas por Starlette:
* <ahref="https://www.python-httpx.org"target="_blank"><code>httpx</code></a> - Requerido si deseas usar el `TestClient`.
* <ahref="https://jinja.palletsprojects.com"target="_blank"><code>jinja2</code></a> - Requerido si deseas usar la configuración de plantilla predeterminada.
* <ahref="https://github.com/Kludex/python-multipart"target="_blank"><code>python-multipart</code></a> - Requerido si deseas soportar <abbrtitle="convertir el string que viene de un request HTTP en datos de Python">"parsing"</abbr> de forms, con `request.form()`.
Usadas por FastAPI / Starlette:
* <ahref="https://www.uvicorn.org"target="_blank"><code>uvicorn</code></a> - para el servidor que carga y sirve tu aplicación. Esto incluye `uvicorn[standard]`, que incluye algunas dependencias (por ejemplo, `uvloop`) necesarias para servir con alto rendimiento.
* `fastapi-cli` - para proporcionar el comando `fastapi`.
### Sin Dependencias `standard`
Si no deseas incluir las dependencias opcionales `standard`, puedes instalar con `pip install fastapi` en lugar de `pip install "fastapi[standard]"`.
### Dependencias Opcionales Adicionales
Usados por Starlette:
Existen algunas dependencias adicionales que podrías querer instalar.
* <ahref="https://www.python-httpx.org"target="_blank"><code>httpx</code></a> - Requerido si quieres usar el `TestClient`.
* <ahref="https://jinja.palletsprojects.com"target="_blank"><code>jinja2</code></a> - Requerido si quieres usar la configuración por defecto de templates.
* <ahref="https://github.com/Kludex/python-multipart"target="_blank"><code>python-multipart</code></a> - Requerido si quieres dar soporte a <abbrtitle="convertir el string que viene de un HTTP request a datos de Python">"parsing"</abbr> de formularios, con `request.form()`.
* <ahref="https://pythonhosted.org/itsdangerous/"target="_blank"><code>itsdangerous</code></a> - Requerido para dar soporte a `SessionMiddleware`.
* <ahref="https://pyyaml.org/wiki/PyYAMLDocumentation"target="_blank"><code>pyyaml</code></a> - Requerido para dar soporte al `SchemaGenerator` de Starlette (probablemente no lo necesites con FastAPI).
* <ahref="https://graphene-python.org/"target="_blank"><code>graphene</code></a> - Requerido para dar soporte a `GraphQLApp`.
Dependencias opcionales adicionales de Pydantic:
Usado por FastAPI / Starlette:
* <ahref="https://docs.pydantic.dev/latest/usage/pydantic_settings/"target="_blank"><code>pydantic-settings</code></a> - para la gestión de configuraciones.
* <ahref="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/"target="_blank"><code>pydantic-extra-types</code></a> - para tipos extra para ser usados con Pydantic.
* <ahref="https://www.uvicorn.org"target="_blank"><code>uvicorn</code></a> - para el servidor que carga y sirve tu aplicación.
* <ahref="https://github.com/ijl/orjson"target="_blank"><code>orjson</code></a> - Requerido si quieres usar `ORJSONResponse`.
* <ahref="https://github.com/esnme/ultrajson"target="_blank"><code>ujson</code></a> - Requerido si quieres usar `UJSONResponse`.
Dependencias opcionales adicionales de FastAPI:
Puedes instalarlos con `pip install fastapi[all]`.
* <ahref="https://github.com/ijl/orjson"target="_blank"><code>orjson</code></a> - Requerido si deseas usar `ORJSONResponse`.
* <ahref="https://github.com/esnme/ultrajson"target="_blank"><code>ujson</code></a> - Requerido si deseas usar `UJSONResponse`.
## Licencia
Este proyecto está licenciado bajo los términos de la licencia del MIT.
Este proyecto tiene licencia bajo los términos de la licencia MIT.
Las plantillas, aunque típicamente vienen con una configuración específica, están diseñadas para ser flexibles y personalizables. Esto te permite modificarlas y adaptarlas a los requisitos de tu proyecto, lo que las convierte en un excelente punto de partida. 🏁
Las plantillas, aunque normalmente vienen con una configuración específica, están diseñadas para ser flexibles y personalizables. Esto te permite modificarlas y adaptarlas a los requisitos de tu proyecto, haciéndolas un excelente punto de partida. 🏁
Puedes utilizar esta plantilla para comenzar, ya que incluye gran parte de la configuración inicial, seguridad, base de datos y algunos endpoints de API ya realizados.
Puedes usar esta plantilla para comenzar, ya que incluye gran parte de la configuración inicial, seguridad, base de datos y algunos endpoints de API ya hechos para ti.
Repositorio en GitHub: [Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template)
Repositorio de GitHub: <ahref="https://github.com/tiangolo/full-stack-fastapi-template"class="external-link"target="_blank">Plantilla Full Stack FastAPI</a>
## Plantilla de FastAPI Full Stack - Tecnología y Características
## Plantilla Full Stack FastAPI - Tecnología y Funcionalidades
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) para el backend API en Python.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para las interacciones con la base de datos SQL en Python (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), utilizado por FastAPI, para la validación de datos y la gestión de configuraciones.
- 💾 [PostgreSQL](https://www.postgresql.org) como la base de datos SQL.
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) para la API del backend en Python.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para las interacciones con bases de datos SQL en Python (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), utilizado por FastAPI, para la validación de datos y gestión de configuraciones.
- 💾 [PostgreSQL](https://www.postgresql.org) como base de datos SQL.
- 🚀 [React](https://react.dev) para el frontend.
- 💃 Usando TypeScript, hooks, [Vite](https://vitejs.dev) y otras partes de un stack de frontend moderno.
- 💃 Usando TypeScript, hooks, [Vite](https://vitejs.dev), y otras partes de una stack moderna de frontend.
- 🎨 [Chakra UI](https://chakra-ui.com) para los componentes del frontend.
- 🤖 Un cliente frontend generado automáticamente.
- 🤖 Un cliente de frontend generado automáticamente.
- 🧪 [Playwright](https://playwright.dev) para pruebas End-to-End.
- 🦇 Soporte para modo oscuro.
- 🐋 [Docker Compose](https://www.docker.com) para desarrollo y producción.
- 🔒 Hashing seguro de contraseñas por defecto.
- 🔑 Autenticación con token JWT.
- 🔑 Autenticación con tokens JWT.
- 📫 Recuperación de contraseñas basada en email.
- ✅ Tests con [Pytest](https://pytest.org).
- ✅ Pruebas con [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) como proxy inverso / balanceador de carga.
- 🚢 Instrucciones de despliegue utilizando Docker Compose, incluyendo cómo configurar un proxy frontend Traefik para manejar certificados HTTPS automáticos.
- 🚢 Instrucciones de despliegue usando Docker Compose, incluyendo cómo configurar un proxy Traefik frontend para manejar certificados HTTPS automáticos.
- 🏭 CI (integración continua) y CD (despliegue continuo) basados en GitHub Actions.
**Python 3.6+** tiene soporte para <abbrtitle="en español, anotaciones de tipo. En inglés también se conocen como: type annotations">"type hints"</abbr> opcionales.
Python tiene soporte para "anotaciones de tipos" opcionales (también llamadas "type hints").
Estos **type hints** son una nueva sintaxis, desde Python 3.6+, que permite declarar el <abbrtitle="por ejemplo: str, int, float, bool">tipo</abbr> de una variable.
Estas **"anotaciones de tipos"** o type hints son una sintaxis especial que permite declarar el <abbrtitle="por ejemplo: str, int, float, bool">tipo</abbr> de una variable.
Usando las declaraciones de tipos para tus variables, los editores y otras herramientas pueden proveerte un soporte mejor.
Al declarar tipos para tus variables, los editores y herramientas te pueden proporcionar un mejor soporte.
Este es solo un **tutorial corto** sobre los Python type hints. Solo cubre lo mínimo necesario para usarlos con **FastAPI**... realmente es muy poco lo que necesitas.
Este es solo un **tutorial rápido / recordatorio** sobre las anotaciones de tipos en Python. Cubre solo lo mínimo necesario para usarlas con **FastAPI**... que en realidad es muy poco.
Todo **FastAPI** está basado en estos type hints, lo que le da muchas ventajas y beneficios.
**FastAPI** se basa completamente en estas anotaciones de tipos, dándole muchas ventajas y beneficios.
Pero, así nunca uses **FastAPI** te beneficiarás de aprender un poco sobre los type hints.
Pero incluso si nunca usas **FastAPI**, te beneficiaría aprender un poco sobre ellas.
/// note | Nota
Si eres un experto en Python y ya lo sabes todo sobre los type hints, salta al siguiente capítulo.
Si eres un experto en Python, y ya sabes todo sobre las anotaciones de tipos, salta al siguiente capítulo.
///
@ -24,8 +24,7 @@ Comencemos con un ejemplo simple:
{* ../../docs_src/python_types/tutorial001.py *}
Llamar este programa nos muestra el siguiente <abbrtitle="en español: salida">output</abbr>:
Llamar a este programa genera:
```
John Doe
@ -33,38 +32,37 @@ John Doe
La función hace lo siguiente:
* Toma un `first_name` y un `last_name`.
* Convierte la primera letra de cada uno en una letra mayúscula con `title()`.
* Las <abbrtitle="las junta como si fuesen una. Con el contenido de una después de la otra. En inglés: concatenate.">concatena</abbr>con un espacio en la mitad.
* Toma un `first_name` y `last_name`.
* Convierte la primera letra de cada uno a mayúsculas con `title()`.
* <abbrtitle="Los une, como uno. Con el contenido de uno después del otro.">Concatena</abbr>ambos con un espacio en el medio.
Hay algunas estructuras de datos que pueden contener otros valores, como `dict`, `list`, `set` y `tuple`. Y los valores internos también pueden tener su propio tipo.
Estos tipos que tienen tipos internos se denominan tipos "**genéricos**". Y es posible declararlos, incluso con sus tipos internos.
Para declarar esos tipos y los tipos internos, puedes usar el módulo estándar de Python `typing`. Existe específicamente para soportar estas anotaciones de tipos.
#### Versiones más recientes de Python
La sintaxis que utiliza `typing` es **compatible** con todas las versiones, desde Python 3.6 hasta las versiones más recientes, incluyendo Python 3.9, Python 3.10, etc.
### Tipos con sub-tipos
A medida que avanza Python, las **versiones más recientes** vienen con soporte mejorado para estas anotaciones de tipos y en muchos casos ni siquiera necesitarás importar y usar el módulo `typing` para declarar las anotaciones de tipos.
Existen algunas estructuras de datos que pueden contener otros valores, como `dict`, `list`, `set` y `tuple`. Los valores internos pueden tener su propio tipo también.
Si puedes elegir una versión más reciente de Python para tu proyecto, podrás aprovechar esa simplicidad adicional.
Para declarar esos tipos y sub-tipos puedes usar el módulo estándar de Python `typing`.
En toda la documentación hay ejemplos compatibles con cada versión de Python (cuando hay una diferencia).
Él existe específicamente para dar soporte a este tipo de type hints.
Por ejemplo, "**Python 3.6+**" significa que es compatible con Python 3.6 o superior (incluyendo 3.7, 3.8, 3.9, 3.10, etc). Y "**Python 3.9+**" significa que es compatible con Python 3.9 o superior (incluyendo 3.10, etc).
Si puedes usar las **últimas versiones de Python**, utiliza los ejemplos para la última versión, esos tendrán la **mejor y más simple sintaxis**, por ejemplo, "**Python 3.10+**".
#### Lista
Por ejemplo, vamos a definir una variable para ser una `list` de `str`.
//// tab | Python 3.9+
Declara la variable, con la misma sintaxis de dos puntos (`:`).
Como tipo, pon `list`.
Como la lista es un tipo que contiene algunos tipos internos, los pones entre corchetes:
* Los keys de este `dict` son de tipo `str` (Digamos que son el nombre de cada ítem).
* Los valores de este `dict` son de tipo `float` (Digamos que son el precio de cada ítem).
* Las claves de este `dict` son del tipo `str` (digamos, el nombre de cada ítem).
* Los valores de este `dict` son del tipo `float` (digamos, el precio de cada ítem).
#### Union
Puedes declarar que una variable puede ser cualquier de **varios tipos**, por ejemplo, un `int` o un `str`.
En Python 3.6 y posterior (incluyendo Python 3.10) puedes usar el tipo `Union` de `typing` y poner dentro de los corchetes los posibles tipos a aceptar.
En Python 3.10 también hay una **nueva sintaxis** donde puedes poner los posibles tipos separados por una <abbrtitle='también llamado "operador OR a nivel de bits", pero ese significado no es relevante aquí'>barra vertical (`|`)</abbr>.
En ambos casos, esto significa que `item` podría ser un `int` o un `str`.
#### Posiblemente `None`
Puedes declarar que un valor podría tener un tipo, como `str`, pero que también podría ser `None`.
En Python 3.6 y posteriores (incluyendo Python 3.10) puedes declararlo importando y usando `Optional` del módulo `typing`.
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009.py!}
```
Usar `Optional[str]` en lugar de solo `str` te permitirá al editor ayudarte a detectar errores donde podrías estar asumiendo que un valor siempre es un `str`, cuando en realidad también podría ser `None`.
`Optional[Something]` es realmente un atajo para `Union[Something, None]`, son equivalentes.
Esto también significa que en Python 3.10, puedes usar `Something | None`:
Si estás usando una versión de Python inferior a 3.10, aquí tienes un consejo desde mi punto de vista muy **subjetivo**:
* 🚨 Evita usar `Optional[SomeType]`
* En su lugar ✨ **usa `Union[SomeType, None]`** ✨.
Ambos son equivalentes y debajo son lo mismo, pero recomendaría `Union` en lugar de `Optional` porque la palabra "**opcional**" parecería implicar que el valor es opcional, y en realidad significa "puede ser `None`", incluso si no es opcional y aún es requerido.
Creo que `Union[SomeType, None]` es más explícito sobre lo que significa.
Se trata solo de las palabras y nombres. Pero esas palabras pueden afectar cómo tú y tus compañeros de equipo piensan sobre el código.
El parámetro `name` está definido como `Optional[str]`, pero **no es opcional**, no puedes llamar a la función sin el parámetro:
```Python
say_hi() # ¡Oh, no, esto lanza un error! 😱
```
El parámetro `name` sigue siendo **requerido** (no *opcional*) porque no tiene un valor predeterminado. Aún así, `name` acepta `None` como valor:
```Python
say_hi(name=None) # Esto funciona, None es válido 🎉
```
La buena noticia es que, una vez que estés en Python 3.10, no tendrás que preocuparte por eso, ya que podrás simplemente usar `|` para definir uniones de tipos:
Y entonces no tendrás que preocuparte por nombres como `Optional` y `Union`. 😎
#### Tipos genéricos
Estos tipos que toman parámetros de tipo en corchetes se llaman **Tipos Genéricos** o **Genéricos**, por ejemplo:
//// tab | Python 3.10+
Puedes usar los mismos tipos integrados como genéricos (con corchetes y tipos dentro):
* `list`
* `tuple`
* `set`
* `dict`
Y lo mismo que con Python 3.8, desde el módulo `typing`:
* `Union`
* `Optional` (lo mismo que con Python 3.8)
* ...y otros.
En Python 3.10, como alternativa a usar los genéricos `Union` y `Optional`, puedes usar la <abbrtitle='también llamado "operador OR a nivel de bits", pero ese significado no es relevante aquí'>barra vertical (`|`)</abbr> para declarar uniones de tipos, eso es mucho mejor y más simple.
////
//// tab | Python 3.9+
Puedes usar los mismos tipos integrados como genéricos (con corchetes y tipos dentro):
* `list`
* `tuple`
* `set`
* `dict`
Y lo mismo que con Python 3.8, desde el módulo `typing`:
* `Union`
* `Optional`
* ...y otros.
////
//// tab | Python 3.8+
* `List`
* `Tuple`
* `Set`
* `Dict`
* `Union`
* `Optional`
* ...y otros.
////
### Clases como tipos
También puedes declarar una clase como el tipo de una variable.
Digamos que tienes una clase `Person`con un nombre:
Digamos que tienes una clase `Person`, con un nombre:
<ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic</a> es un paquete de Python para realizar la validación de datos.
## Modelos de Pydantic
Declaras la "forma" de los datos como clases con atributos.
<ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic</a> es una library de Python para llevar a cabo validación de datos.
Y cada atributo tiene un tipo.
Tú declaras la "forma" de los datos mediante clases con atributos.
Entonces creas un instance de esa clase con algunos valores y validará los valores, los convertirá al tipo adecuado (si es el caso) y te dará un objeto con todos los datos.
Cada atributo tiene un tipo.
Y obtienes todo el soporte del editor con ese objeto resultante.
Luego creas un instance de esa clase con algunos valores y Pydantic validará los valores, los convertirá al tipo apropiado (si ese es el caso) y te dará un objeto con todos los datos.
Un ejemplo de la documentación oficial de Pydantic:
Y obtienes todo el soporte del editor con el objeto resultante.
Para aprender más sobre <ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic mira su documentación</a>.
Para saber más sobre <ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic, revisa su documentación</a>.
///
**FastAPI** está todo 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}.
/// tip | Consejo
Pydantic tiene un comportamiento especial cuando utilizas `Optional` o `Union[Something, None]` sin un valor por defecto, puedes leer más sobre ello en la documentación de Pydantic sobre <ahref="https://docs.pydantic.dev/2.3/usage/models/#required-fields"class="external-link"target="_blank">Required Optional fields</a>.
///
## Anotaciones de tipos con metadata
Python también tiene una funcionalidad que permite poner **<abbrtitle="Datos sobre los datos, en este caso, información sobre el tipo, por ejemplo, una descripción.">metadata</abbr> adicional** en estas anotaciones de tipos usando `Annotated`.
//// tab | Python 3.9+
Vas a ver mucho más de esto en práctica en el [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
En Python 3.9, `Annotated` es parte de la librería estándar, así que puedes importarlo desde `typing`.
En versiones por debajo de Python 3.9, importas `Annotated` de `typing_extensions`.
Ya estará instalado con **FastAPI**.
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial013.py!}
```
////
Python en sí no hace nada con este `Annotated`. Y para los editores y otras herramientas, el tipo sigue siendo `str`.
Pero puedes usar este espacio en `Annotated` para proporcionar a **FastAPI** metadata adicional sobre cómo quieres que se comporte tu aplicación.
Lo importante a recordar es que **el primer *parámetro de tipo*** que pasas a `Annotated` es el **tipo real**. El resto es solo metadata para otras herramientas.
Por ahora, solo necesitas saber que `Annotated` existe, y que es Python estándar. 😎
Luego verás lo **poderoso** que puede ser.
/// tip | Consejo
El hecho de que esto sea **Python estándar** significa que seguirás obteniendo la **mejor experiencia de desarrollador posible** en tu editor, con las herramientas que usas para analizar y refactorizar tu código, etc. ✨
Y también que tu código será muy compatible con muchas otras herramientas y paquetes de Python. 🚀
///
## Type hints en **FastAPI**
## Anotaciones de tipos en **FastAPI**
**FastAPI** aprovecha estos type hints para hacer varias cosas.
**FastAPI** aprovecha estas anotaciones de tipos para hacer varias cosas.
Con **FastAPI** declaras los parámetros con type hints y obtienes:
Con **FastAPI** declaras parámetros con anotaciones de tipos y obtienes:
* **Soporte en el editor**.
* **Type checks**.
* **Soporte del editor**.
* **Chequeo de tipos**.
...y **FastAPI** usa las mismas declaraciones para:
* **Definir requerimientos**: desde request path parameters, query parameters, headers, bodies, dependencies, etc.
* **Convertir datos**: desde el request al tipo requerido.
* **Validar datos**: viniendo de cada request:
* **Definir requerimientos**: de parámetros de path de la request, parámetros de query, headers, bodies, dependencias, etc.
* **Convertir datos**: de la request al tipo requerido.
* **Validar datos**: provenientes de cada request:
* Generando **errores automáticos** devueltos al cliente cuando los datos son inválidos.
* **Documentar** la API usando OpenAPI:
* que en su caso es usada por las interfaces de usuario de la documentación automática e interactiva.
* Que luego es usada por las interfaces de documentación interactiva automática.
Puede que todo esto suene abstracto. Pero no te preocupes que todo lo verás en acción en el [Tutorial - User Guide](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){.internal-link target=_blank}.
Lo importante es que usando los tipos de Python estándar en un único lugar (en vez de añadir más clases, decorator, etc.) **FastAPI** hará mucho 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
Si ya pasaste por todo el tutorial y volviste a la sección de los tipos, una buena referencia 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 <ahref="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html"class="external-link"target="_blank">la "cheat sheet" de `mypy`</a>.
<fontcolor="#4E9A06">INFO</font>: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
<fontcolor="#4E9A06">INFO</font>: Uvicorn running on <b>http://127.0.0.1:8000</b> (Press CTRL+C to quit)
<fontcolor="#4E9A06">INFO</font>: Started reloader process [<fontcolor="#34E2E2"><b>2265862</b></font>] using <fontcolor="#34E2E2"><b>WatchFiles</b></font>
<fontcolor="#4E9A06">INFO</font>: Started server process [<fontcolor="#06989A">2265873</font>]
<fontcolor="#4E9A06">INFO</font>: Waiting for application startup.
* `main`: el archivo `main.py` (el "módulo" de Python).
* `app`: el objeto creado dentro de `main.py` con la línea `app = FastAPI()`.
* `--reload`: hace que el servidor se reinicie cada vez que cambia el código. Úsalo únicamente para desarrollo.
///
En el output, hay una línea que dice más o menos:
En el resultado, hay una línea con algo como:
```hl_lines="4"
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
Esa línea muestra la URL dónde se está sirviendo tu app en tu maquina local.
Esa línea muestra la URL donde tu aplicación está siendo servida, en tu máquina local.
### Revísalo
### Compruébalo
Abre tu navegador en <ahref="http://127.0.0.1:8000"class="external-link"target="_blank">http://127.0.0.1:8000</a>.
Verás la respuesta en JSON:
Verás el response JSON como:
```JSON
{"message": "Hello World"}
@ -52,55 +76,55 @@ Verás la respuesta en JSON:
### Documentación interactiva de la API
Ahora dirígete 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 <ahref="http://127.0.0.1:8000/docs"class="external-link"target="_blank">http://127.0.0.1:8000/docs</a>.
Ahí verás la documentación automática e interactiva de la API (proveída 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 <ahref="https://github.com/swagger-api/swagger-ui"class="external-link"target="_blank">Swagger UI</a>):
Ahora, dirígete 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 <ahref="http://127.0.0.1:8000/redoc"class="external-link"target="_blank">http://127.0.0.1:8000/redoc</a>.
Aquí verás la documentación automática alternativa (proveída por <ahref="https://github.com/Rebilly/ReDoc"class="external-link"target="_blank">ReDoc</a>):
Verás la documentación alternativa automática (proporcionada por <ahref="https://github.com/Rebilly/ReDoc"class="external-link"target="_blank">ReDoc</a>):
**FastAPI** genera un "schema" con toda tu API usando el estándar para definir APIs, **OpenAPI**.
**FastAPI** genera un "esquema" con toda tu API utilizando el estándar **OpenAPI** para definir APIs.
#### "Schema"
#### "Esquema"
Un "schema" es una definición o descripción de algo. No es el código que la implementa, sino solo una descripción abstracta.
Un "esquema" es una definición o descripción de algo. No el código que lo implementa, sino solo una descripción abstracta.
#### "Schema" de la API
#### Esquema de la API
En este caso, <ahref="https://github.com/OAI/OpenAPI-Specification"class="external-link"target="_blank">OpenAPI</a> es una especificación que dicta como se debe definir el schema de tu API.
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.
La definición del schema incluye los paths de tu API, los parámetros que podría recibir, etc.
Esta definición de esquema incluye los paths de tu API, los posibles parámetros que toman, etc.
#### "Schema" de datos
#### Esquema de Datos
El concepto "schema" también se puede referir a la forma de algunos datos, como un contenido en formato JSON.
El término "esquema" también podría referirse a la forma de algunos datos, como el contenido JSON.
En ese caso haría referencia a los atributos del JSON, los tipos de datos que tiene, etc.
En ese caso, significaría los atributos del JSON, los tipos de datos que tienen, etc.
#### OpenAPI y JSON Schema
OpenAPI define un schema de API para tu API. Ese schema incluye definiciones (o "schemas") de los datos enviados y recibidos por tu API usando **JSON Schema**, el estándar para los schemas de datos en JSON.
OpenAPI define un esquema de API para tu API. Y ese esquema incluye definiciones (o "esquemas") de los datos enviados y recibidos por tu API utilizando **JSON Schema**, el estándar para esquemas de datos JSON.
#### Revisa el `openapi.json`
Si sientes curiosidad por saber cómo se ve el schema de OpenAPI en bruto, FastAPI genera automáticamente un (schema) JSON con la descripción de todo 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.
Lo puedes ver directamente en: <ahref="http://127.0.0.1:8000/openapi.json"class="external-link"target="_blank">http://127.0.0.1:8000/openapi.json</a>.
Esto te mostrará un JSON que comienza con algo como:
Mostrará un JSON que empieza con algo como:
```JSON
{
"openapi": "3.0.2",
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
@ -119,73 +143,45 @@ Esto te mostrará un JSON que comienza con algo como:
...
```
#### ¿Para qué se usa OpenAPI?
#### Para qué sirve OpenAPI
El schema de OpenAPI es lo que alimenta a los dos sistemas de documentación interactiva incluidos.
El esquema OpenAPI es lo que impulsa los dos sistemas de documentación interactiva incluidos.
También hay docenas de alternativas, todas basadas en OpenAPI. Podrías añadir fácilmente cualquiera de esas alternativas a tu aplicación construida con **FastAPI**.
Y hay docenas de alternativas, todas basadas en OpenAPI. Podrías añadir fácilmente cualquiera de esas alternativas a tu aplicación construida con **FastAPI**.
También podrías usarlo para generar código automáticamente, para los clientes que se comunican con tu API. Por ejemplo, frontend, móvil o aplicaciones de 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.
Un "path" también se conoce habitualmente como "endpoint", "route" o "ruta".
Un "path" también es comúnmente llamado "endpoint" o "ruta".
///
Cuando construyes una API, el "path" es la manera principal de separar los <abbrtitle="en inglés: separation of concerns">"intereses"</abbr> y los "recursos".
Mientras construyes una API, el "path" es la forma principal de separar "concerns" y "resources".
#### Operación
"Operación" aquí se refiere a uno de los "métodos" de HTTP.
"Operación" aquí se refiere a uno de los "métodos" HTTP.
Uno como:
Uno de:
* `POST`
* `GET`
@ -223,43 +219,43 @@ Uno como:
* `PATCH`
* `TRACE`
En el protocolo de HTTP, te puedes comunicar con cada path usando uno (o más) de estos "métodos".
En el protocolo HTTP, puedes comunicarte con cada path usando uno (o más) de estos "métodos".
---
Cuando construyes APIs, normalmente usas uno de estos métodos específicos de HTTP para realizar una acción específica.
Al construir APIs, normalmente usas estos métodos HTTP específicos para realizar una acción específica.
Normalmente usas:
* `POST`: para crear datos.
* `GET`: para leer datos.
* `PUT`: para actualizar datos.
* `DELETE`: para borrar datos.
* `DELETE`: para eliminar datos.
Así que en OpenAPI, cada uno de estos métodos de HTTP es referido como una "operación".
Así que, en OpenAPI, cada uno de los métodos HTTP se llama una "operation".
Puedes devolver`dict`, `list`, valores singulares como un`str`, `int`, etc.
Puedes retornar un`dict`, `list`, valores singulares como `str`, `int`, etc.
También puedes devolver modelos de Pydantic (ya verás más sobre esto más adelante).
También puedes retornar modelos de Pydantic (verás más sobre eso más adelante).
Hay muchos objetos y modelos que pueden ser convertidos automáticamente a JSON (incluyendo ORMs, etc.). Intenta usar tus favoritos, es muy probable que ya tengan soporte.
Hay muchos otros objetos y modelos que serán automáticamente convertidos a JSON (incluyendo ORMs, etc). Intenta usar tus favoritos, es altamente probable que ya sean compatibles.
## Repaso
## Recapitulación
* Importa `FastAPI`.
* Crea un instance de`app`.
* Escribe un **decorador de operación de path** (como `@app.get("/")`).
* Escribe una **función de la operación de path** (como `def root(): ...` arriba).
* Corre el servidor de desarrollo (como `uvicorn main:app --reload`).
* Crea una instancia`app`.
* Escribe un **path operation decorator** usando decoradores como `@app.get("/")`.
* Define una **path operation function**; por ejemplo, `def root(): ...`.
* Ejecuta el servidor de desarrollo usando el comando `fastapi dev`.
Este tutorial te muestra cómo usar **FastAPI** con la mayoría de sus características paso a paso.
Este tutorial te muestra cómo usar **FastAPI** con la mayoría de sus funcionalidades, paso a paso.
Cada sección se basa gradualmente en las anteriores, pero está estructurada en temas separados, así puedes ir directamente a cualquier tema en concreto para resolver tus necesidades específicas sobre la API.
Cada sección se basa gradualmente en las anteriores, pero está estructurada para separar temas, de manera que puedas ir directamente a cualquier sección específica para resolver tus necesidades específicas de API.
Funciona también como una referencia futura, para que puedas volver y ver exactamente lo que necesitas.
También está diseñado para funcionar como una referencia futura para que puedas volver y ver exactamente lo que necesitas.
## Ejecuta el código
Todos los bloques de código se pueden copiar y usar directamente (en realidad son archivos Python probados).
Todos los bloques de código pueden ser copiados y usados directamente (de hecho, son archivos Python probados).
Para ejecutar cualquiera de los ejemplos, copia el código en un archivo llamado `main.py`, y ejecuta `uvicorn` de la siguiente manera en tu terminal:
Para ejecutar cualquiera de los ejemplos, copia el código a un archivo `main.py`, y comienza `fastapi dev` con:
<divclass="termy">
```console
$ uvicorn main:app --reload
<spanstyle="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<spanstyle="color: green;">INFO</span>: Started reloader process [28720]
<spanstyle="color: green;">INFO</span>: Started server process [28722]
<spanstyle="color: green;">INFO</span>: Waiting for application startup.
<fontcolor="#4E9A06">INFO</font>: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
<fontcolor="#4E9A06">INFO</font>: Uvicorn running on <b>http://127.0.0.1:8000</b> (Press CTRL+C to quit)
<fontcolor="#4E9A06">INFO</font>: Started reloader process [<fontcolor="#34E2E2"><b>2265862</b></font>] using <fontcolor="#34E2E2"><b>WatchFiles</b></font>
<fontcolor="#4E9A06">INFO</font>: Started server process [<fontcolor="#06989A">2265873</font>]
<fontcolor="#4E9A06">INFO</font>: Waiting for application startup.
Se **RECOMIENDA** que escribas o copies el código, lo edites y lo ejecutes localmente.
Es **ALTAMENTE recomendable** que escribas o copies el código, lo edites y lo ejecutes localmente.
Usarlo en tu editor de código es lo que realmente te muestra los beneficios de FastAPI, al ver la poca cantidad de código que tienes que escribir, todas las verificaciones de tipo, auto-completado, etc.
Usarlo en tu editor es lo que realmente te muestra los beneficios de FastAPI, al ver cuán poco código tienes que escribir, todos los chequeos de tipos, autocompletado, etc.
---
## Instala FastAPI
## Instalar FastAPI
El primer paso es instalar FastAPI.
Para el tutorial, es posible que quieras instalarlo con todas las dependencias y características opcionales:
Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, actívalo, y luego **instala FastAPI**:
<divclass="termy">
```console
$ pip install "fastapi[all]"
$ pip install "fastapi[standard]"
---> 100%
```
</div>
...eso también incluye `uvicorn` que puedes usar como el servidor que ejecuta tu código.
/// note | Nota
También puedes instalarlo parte por parte.
Esto es lo que probablemente harías una vez que desees implementar tu aplicación en producción:
```
pip install fastapi
```
También debes instalar `uvicorn` para que funcione como tu servidor:
```
pip install "uvicorn[standard]"
```
Cuando instalas con `pip install "fastapi[standard]"` viene con algunas dependencias opcionales estándar por defecto.
Y lo mismo para cada una de las dependencias opcionales que quieras utilizar.
Si no quieres tener esas dependencias opcionales, en su lugar puedes instalar `pip install fastapi`.
///
## Guía Avanzada de Usuario
## Guía Avanzada del Usuario
También hay una **Guía Avanzada de Usuario** que puedes leer luego de este **Tutorial - Guía de Usuario**.
También hay una **Guía Avanzada del Usuario** que puedes leer después de esta **Tutorial - Guía del Usuario**.
La **Guía Avanzada de Usuario**, se basa en este tutorial, utiliza los mismos conceptos y enseña algunas características adicionales.
La **Guía Avanzada del Usuario** se basa en esta, utiliza los mismos conceptos y te enseña algunas funcionalidades adicionales.
Pero primero deberías leer el **Tutorial - Guía de Usuario** (lo que estas leyendo ahora mismo).
Pero primero deberías leer la **Tutorial - Guía del Usuario** (lo que estás leyendo ahora mismo).
La guía esa diseñada para que puedas crear una aplicación completa con solo el **Tutorial - Guía de Usuario**, y luego extenderlo de diferentes maneras, según tus necesidades, utilizando algunas de las ideas adicionales de la **Guía Avanzada de Usuario**.
Está diseñada para que puedas construir una aplicación completa solo con la **Tutorial - Guía del Usuario**, y luego extenderla de diferentes maneras, dependiendo de tus necesidades, utilizando algunas de las ideas adicionales de la **Guía Avanzada del Usuario**.
El valor del parámetro de path `item_id` será pasado 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`.
Entonces, si corres 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 una respuesta de:
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:
```JSON
{"item_id":"foo"}
@ -14,21 +14,21 @@ Entonces, si corres este ejemplo y vas a <a href="http://127.0.0.1:8000/items/fo
## Parámetros de path con tipos
Puedes declarar el tipo de un parámetro de path en la función usando las anotaciones de tipos estándar de Python:
Puedes declarar el tipo de un parámetro de path en la función, usando anotaciones de tipos estándar de Python:
En este caso, `item_id`es declarado como un `int`.
En este caso, `item_id` se declara como un `int`.
/// check | Revisa
Esto te dará soporte en el editor dentro de tu función, con chequeo de errores, auto-completado, etc.
Esto te dará soporte del editor dentro de tu función, con chequeo de errores, autocompletado, etc.
///
## <abbrtitle="también conocido en inglés como: serialization, parsing, marshalling">Conversión</abbr> de datos
## Conversión de datos
Si corres 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 una respuesta de:
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:
```JSON
{"item_id":3}
@ -36,160 +36,168 @@ Si corres este ejemplo y abres tu navegador en <a href="http://127.0.0.1:8000/it
/// check | Revisa
Observa que el valor que recibió (y devolvió) tu función es `3`, como un Python `int`, y no un string `"3"`.
Nota que el valor que tu función recibió (y devolvió) es `3`, como un `int` de Python, no un string `"3"`.
Entonces, con esa declaración de tipos **FastAPI** te da<abbrtitle="convertir el string que viene de un HTTP request a datos de Python">"parsing"</abbr> automático del request.
Entonces, con esa declaración de tipo, **FastAPI** te ofrece<abbrtitle="converting the string that comes from an HTTP request into Python data">"parsing"</abbr> automático de requests.
///
## Validación de datos
Pero si abres tu 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 este lindo error de HTTP:
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:
```JSON
{
"detail": [
{
"type": "int_parsing",
"loc": [
"path",
"item_id"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
"msg": "Input should be a valid integer, unable to parse string as an integer",
debido a que el parámetro de path `item_id` tenía el valor`"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 pasaras un `float` en vez 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: <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>
/// check | Revisa
Así, con la misma declaración de tipo de Python, **FastAPI** te da validación de datos.
Entonces, con la misma declaración de tipo de Python, **FastAPI** te ofrece validación de datos.
Observa que el error también muestra claramente el punto exacto en el que no pasó la validación.
Nota que el error también indica claramente el punto exacto donde la validación falló.
Esto es increíblemente útil cuando estás desarrollando y debugging código que interactúa con tu API.
Esto es increíblemente útil mientras desarrollas y depuras código que interactúa con tu API.
///
## Documentación
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 la documentación automática e interactiva del API como:
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:
<imgsrc="/img/tutorial/path-params/image01.png">
/// check | Revisa
Nuevamente, con la misma declaración de tipo de Python, **FastAPI** te da documentación automática e interactiva (integrándose con Swagger UI)
Nuevamente, solo con esa misma declaración de tipo de Python, **FastAPI** te ofrece documentación automática e interactiva (integrando Swagger UI).
Observa que el parámetro de path está declarado como un integer.
Nota que el parámetro de path está declarado como un entero.
///
## Beneficios basados en estándares, documentación alternativa
Debido a que el schema generado es del estándar <ahref="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md"class="external-link"target="_blank">OpenAPI</a> hay muchas herramientas compatibles.
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.
Es por esto que **FastAPI** mismo provee una documentación alternativa de la API (usando ReDoc), a la que 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 <ahref="http://127.0.0.1:8000/redoc"class="external-link"target="_blank">http://127.0.0.1:8000/redoc</a>:
<imgsrc="/img/tutorial/path-params/image02.png">
De la misma manera hay muchas herramientas compatibles. Incluyendo herramientas de generación de código para muchos lenguajes.
De la misma manera, hay muchas herramientas compatibles. Incluyendo herramientas de generación de código para muchos lenguajes.
## Pydantic
Toda la validación de datos es realizada tras bastidores por<ahref="https://docs.pydantic.dev/"class="external-link"target="_blank">Pydantic</a>, así que obtienes todos sus beneficios. Así sabes que estás en buenas manos.
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.
Puedes usar las mismas declaraciones de tipos con `str`, `float`, `bool` y otros tipos de datos más complejos.
Puedes usar las mismas declaraciones de tipo con `str`, `float`, `bool` y muchos otros tipos de datos complejos.
Exploraremos varios de estos tipos en los próximos capítulos del tutorial.
Varios de estos se exploran en los siguientes capítulos del tutorial.
## El orden importa
Cuando creas *operaciones de path* puedes encontrarte con situaciones en las que tengas un path fijo.
Al crear *path operations*, puedes encontrarte en situaciones donde tienes un path fijo.
Digamos algo como `/users/me` que sea para obtener datos del usuario actual.
Como `/users/me`, imaginemos que es para obtener datos sobre el usuario actual.
... y luego puedes tener el path `/users/{user_id}` para obtener los datos sobre un usuario específico asociados a un ID de usuario.
Y luego también puedes tener un path `/users/{user_id}` para obtener datos sobre un usuario específico por algún ID de usuario.
Porque las *operaciones de path* son evaluadas en orden, tienes que asegurarte de que el path para `/users/me` sea declarado antes que el path para`/users/{user_id}`:
Debido a que las *path operations* se evalúan en orden, necesitas asegurarte de que el path para `/users/me` se declara antes que el de`/users/{user_id}`:
De otra manera el path para `/users/{user_id}` coincidiría también con `/users/me` "pensando" que está recibiendo el parámetro `user_id` con el valor `"me"`.
De lo contrario, el path para `/users/{user_id}` también coincidiría para `/users/me`, "pensando" que está recibiendo un parámetro `user_id` con un valor de `"me"`.
De manera similar, no puedes redefinir una path operation:
La primera siempre será utilizada ya que el path coincide primero.
## Valores predefinidos
Si tienes una *operación de path* que recibe un *parámetro de path* pero quieres que los valores posibles del *parámetro de path* sean predefinidos puedes usar un <abbrtitle="Enumeration">`Enum`</abbr> estándar de Python.
Si tienes una *path operation* que recibe un *path parameter*, pero quieres que los valores posibles válidos del *path parameter* estén predefinidos, puedes usar un <abbrtitle="Enumeration">`Enum`</abbr> estándar de Python.
### Crea una clase `Enum`
### Crear una clase `Enum`
Importa `Enum` y crea una sub-clase que herede desde `str` y desde `Enum`.
Importa `Enum` y crea una subclase que herede de `str` y de `Enum`.
Al heredar desde`str` la documentación de la API podrá saber que los valores deben ser de tipo `string` y podrá mostrarlos correctamente.
Al heredar de `str`, la documentación de la API podrá saber que los valores deben ser de tipo `string` y podrá representarlos correctamente.
Luego crea atributos de clase con valores fijos, que serán los valores disponibles válidos:
Luego crea atributos de clase con valores fijos, que serán los valores válidos disponibles:
Las <ahref="https://docs.python.org/3/library/enum.html"class="external-link"target="_blank">Enumerations (o enums) están disponibles en Python</a> desde la versión 3.4.
<ahref="https://docs.python.org/3/library/enum.html"class="external-link"target="_blank">Las enumeraciones (o enums) están disponibles en Python</a> desde la versión 3.4.
///
/// tip | Consejo
Si lo estás dudando, "AlexNet", "ResNet", y "LeNet" son solo nombres de <abbrtitle="Técnicamente, arquitecturas de modelos de Deep Learning">modelos</abbr> de Machine Learning.
Si te estás preguntando, "AlexNet", "ResNet" y "LeNet" son solo nombres de <abbrtitle="Técnicamente, arquitecturas de modelos de Deep Learning">modelos</abbr> de Machine Learning.
///
### Declara un *parámetro de path*
### Declarar un *path parameter*
Luego, crea un *parámetro de path* con anotaciones de tipos usando la clase enum que creaste (`ModelName`):
Luego crea un *path parameter* con una anotación de tipo usando la clase enum que creaste (`ModelName`):
En tu cliente obtendrás una respuesta en JSON como:
En tu cliente recibirás un response JSON como:
```JSON
{
@ -198,53 +206,53 @@ En tu cliente obtendrás una respuesta en JSON como:
}
```
## Parámetros de path parameters que contienen paths
## Parámetros de path conteniendo paths
Digamos que tienes una *operación de path* con un path `/files/{file_path}`.
Imaginemos que tienes una *path operation* con un path `/files/{file_path}`.
Pero necesitas que el mismo `file_path` contenga un path como `home/johndoe/myfile.txt`.
Pero necesitas que `file_path`en sí mismo contenga un *path*, como `home/johndoe/myfile.txt`.
Entonces, la URL para ese archivo sería algo como: `/files/home/johndoe/myfile.txt`.
### Soporte de OpenAPI
OpenAPI no soporta una manera de declarar un *parámetro de path* que contenga un path, dado que esto podría llevar a escenarios que son difíciles de probar y definir.
OpenAPI no soporta una manera de declarar un *path parameter* para que contenga un *path* dentro, ya que eso podría llevar a escenarios que son difíciles de probar y definir.
Sin embargo, lo puedes hacer en **FastAPI** usando una de las herramientas internas de Starlette.
Sin embargo, todavía puedes hacerlo en **FastAPI**, usando una de las herramientas internas de Starlette.
La documentación seguirá funcionando, aunque no añadirá ninguna información diciendo que el parámetro debería contener un path.
Y la documentación seguiría funcionando, aunque no agregue ninguna documentación indicando que el parámetro debe contener un path.
### Convertidor de path
### Convertidor de Path
Usando una opción directamente desde Starlette puedes declarar un *parámetro de path* que contenga un path usando una URL como:
Usando una opción directamente de Starlette puedes declarar un *path parameter* conteniendo un *path* usando una URL como:
```
/files/{file_path:path}
```
En este caso el nombre del parámetro es `file_path` y la última parte, `:path`, le dice que el parámetro debería coincidir con cualquier path.
En este caso, el nombre del parámetro es `file_path`, y la última parte, `:path`, indica que el parámetro debería coincidir con cualquier *path*.
Cuando declaras otros parámetros de la función que no hacen parte de los parámetros de path estos se interpretan automáticamente como parámetros de "query".
Cuando declaras otros parámetros de función que no son parte de los parámetros de path, son automáticamente interpretados como parámetros de "query".
También puedes notar que **FastAPI** es lo suficientemente inteligente para darse cuenta de que el parámetro de path `item_id` es un parámetro de path y que `q` no lo es, y por lo tanto es un parámetro de query.
///
/// note | Nota
FastAPI sabrá que `q` es opcional por el `= None`.
El `Union` en `Union[str, None]` no es usado por FastAPI (FastAPI solo usará la parte `str`), pero el `Union[str, None]` le permitirá a tu editor ayudarte a encontrar errores en tu código.
Además, nota que **FastAPI** es lo suficientemente inteligente para notar que el parámetro de path `item_id` es un parámetro de path y `q` no lo es, por lo tanto, es un parámetro de query.
///
## Conversión de tipos de parámetros de query
## Conversión de tipos en parámetros de query
También puedes declarar tipos `bool` y serán convertidos:
También puedes declarar tipos `bool`, y serán convertidos:
o cualquier otra variación (mayúsculas, primera letra en mayúscula, etc.) tu función verá el parámetro `short` con un valor `bool` de `True`. Si no, lo verá como`False`.
o cualquier otra variación (mayúsculas, primera letra en mayúscula, etc.), tu función verá el parámetro `short` con un valor `bool` de `True`. De lo contrario, será`False`.
## Múltiples parámetros de path y query
## Múltiples parámetros de path y de query
Puedes declarar múltiples parámetros de path y parámetros de query al mismo tiempo.**FastAPI** sabe cuál es cuál.
Puedes declarar múltiples parámetros de path y de query al mismo tiempo,**FastAPI** sabe cuál es cuál.
No los tienes que declarar en un orden específico.
Y no tienes que declararlos en un orden específico.
Cuando declaras un valor por defecto para los parámetros que no son de path (por ahora solo hemos visto parámetros de query), entonces no es requerido.
Cuando declaras un valor por defecto para parámetros que no son de path (por ahora, solo hemos visto parámetros de query), entonces no es requerido.
Si no quieres añadir un valor específico sino solo hacerlo opcional, pon el valor por defecto como `None`.
Si no quieres agregar un valor específico pero solo hacer que sea opcional, establece el valor por defecto como `None`.
Pero cuando quieres hacer que un parámetro de query sea requerido, puedes simplemente no declararle un valor por defecto:
Pero cuando quieres hacer un parámetro de query requerido, simplemente no declares ningún valor por defecto:
* `skip`, un `int` con un valor por defecto de `0`.
@ -189,6 +181,6 @@ En este caso hay 3 parámetros de query:
/// tip | Consejo
También podrías usar los `Enum`s de la misma manera que con los [Parámetros de path](path-params.md#valores-predefinidos){.internal-link target=_blank}.
También podrías usar `Enum`s de la misma manera que con [Parámetros de Path](path-params.md#predefined-values){.internal-link target=_blank}.