Saltar al contenido
Apside

FastapiPythonDeveloperAPI

FastAPI de aprendiz a experto con Python 3

Diego Ramirez Henriquez ·

imagen

Saludos. Hoy quiero comenzar una serie donde explicaré el uso del framework FastAPI con Python. Mostraré de una forma simple y rápida cómo sacar el máximo provecho de esta herramienta y explorar todas las posibilidades que ofrece basado en su documentación con ejemplos.

El objetivo de este capitulo es instalar y desplegar la primera versión de nuestra Api.

¿Qué es FastAPI?

FastAPI es un framework para desarrollar APIs con Python, al igual que Flask y otros frameworks para APIs RESTful.

Sus principales ventajas radican en la rapidez de desarrollo y su alta modularidad. A diferencia de otros, no impone una estructura obligatoria, permitiendo escalarla según nuestras necesidades.

Instala FastApi

Para instalar la biblioteca FastAPI, es necesario tener Python instalado en nuestras computadoras, así como su gestor de módulos ‘pip’. En este artículo, se utilizará la versión más reciente de Python (3.12.0). Para la instalación, ejecutaremos el siguiente comando, que instalará tanto FastAPI como Uvicorn.

python -m pip install fastapi uvicorn[standard]

Es fundamental comprender que la biblioteca FastAPI proporciona todas las clases y herramientas necesarias para desarrollar la lógica, estructura y comunicación de la API. Por otro lado, Uvicorn facilita la creación de un servidor local que permite la llamada y el montaje de nuestro servicio.

Ejemplo rapido

Una vez instalada las dependencias empezamos a crear la estructura de nuestro proyecto, para ello crearemos una carpeta con el nombre del proyecto, yo le llamaré “HelloWorld” y dentro de la carpeta crearé la archivo main.py

Abriremos el archivo main con un editor de texto a preferencia de cada uno, en este caso yo usaré Visual Studio Code y escribiremos las siguientes lineas de codigo

# main.py
from fastapi import FastAPI # Importamos la clase FastAPI del paquete fastapi
app = FastAPI() # Instanciamos la clase FastAPI
# Decorador que indica que la función root()
# y se ejecutará cuando se haga una petición GET a la ruta /
@app.get("/")
async def hello_world(): # Definimos la función root()
 '''
    Funcion asíncrona que retorna un diccionario
 '''
 return {"message":"Hello world!"} # Retornamos un diccionario

importante destacar que con el decorador @app.get() podemos definir el metodo que tenga nuestra funcion, otros metodos disponibles listado en la documentacion oficial de FastAPI son @app.post(), @app.put(), @app.delete(), @app.options(), @app.head(), @app.patch() y @app.trace()

Asi de simple podemos montar nuestra primera versión de FastAPI y probarla, para ello ejecutemos el siguiente comando en una consola en el directorio de nuestro proyecto

uvicorn main:app --reload
>> Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

Aquí estaremos dando uso a la biblioteca uvicorn donde definimos el archivo donde esta ubicado el root de nuestro proyecto (donde instanciamos la clase FastAPI) seguido de dos puntos la variable donde guarda la instancia de la clase FastAPI(), añadí el comando “ — reload” para efectos de cuando se hagan cambios automaticamente se redespliegue

FastAPI genera documentación automática

Asi es, lo mejor de todo es que automaticamente FastAPI nos crea una documentación completa y además con urls para probar directamente nuestros metodos, esto es posible gracias a que FastAPI utiliza Swagger UI

por defecto en la instancia de la clase “app = FastAPI()”, el constructor de la clase tiene un parametro llamado “docs_url” que por defecto es “/docs”, es decir que en la base url de nuestra api se creó el endpoint /docs con el metodo GET donde podemos consumirlo desde nuestro navegador.

imagen

imagen

y podemos probar nuestros metodos desde ahi mismo ya que FastAPI utiliza curl

imagen

El constructor de FastAPI y sus configuraciones

Acabamos de ver “docs_url” pero en realidad FastAPI entrega mucho más que eso y configuraciones importantes para seguridad o customizacion de nuestro proyecto, me gustaria abarcar la mayoría o todas en este capitulo.

imagen

Según la definición de la clase esto es todo lo que nos ofrece el constructor de FastApi para poder configurar nuestro proyecto a nuestro gusto.

DEBUG

valor boleano que indica si debe mostrarse los traceback de nuestras excepciones enlos retornos de la aplicación

ejemplo debug = TRUE

from fastapi import FastAPI # Importamos la clase FastAPI del paquete fastapi
app = FastAPI(
 debug=True, # Modo debug activado
) # Instanciamos la clase FastAPI
# Decorador que indica que la función root()
# y se ejecutará cuando se haga una petición GET a la ruta /
@app.get("/")
async def hello_world(): # Definimos la función root()
 '''
    Funcion asíncrona que retorna un diccionario
 '''
 error = 1/0 # Generamos un error para que se vea en el log
 return {"message":"Hello world!"} # Retornamos un diccionario

si llamamos a “/” este deberia ejecutar la sentencia 1/0 lo cual dará una excepcion en el servidor

imagen

a efectos de prueba al llamar este muestra toda la información del fallo, esto es recomendable tenerlo activado durante el desarrollo, pero cuando terminemos nuestro desarrollo es aconsejable desactivar esta opcion.

ejemplo DEBUG = False

imagen

en cambio aqui cuando es falso solo se responderá el servicio con un Internal Server Error.

Routes

Como su nombre indica, las rutas en FastAPI definen los endpoints de nuestros servicios. Es importante destacar que, en la definición, se especifica que esto es una lista de la clase ‘BaseRoute’, la cual veremos en detalle más adelante. Al instanciarse, por defecto, recibe el valor ‘None’, lo que significa que se iniciará sin rutas predefinidas.

BaseRoute es la clase principal en FastAPI que define lo que son los endpoints para nuestro servicio. FastAPI tiene varias clases heredadas de BaseRoute que nos brindan la capacidad de generar rutas. En el ejemplo anterior, al no colocar valores en esa instancia, fui creando las rutas en el transcurso del código utilizando el decorador @app.get(). Esta es una opción válida si deseamos tener todo en el mismo archivo y tenemos acceso a la variable app.

Sin embargo, si estamos en otro archivo y queremos definir rutas en archivos y carpetas diferentes, debemos cambiar la forma en que definimos los endpoints y empezar a utilizar ApiRouter. Explicaré cómo hacer esto en otro capítulo.

Tittle

Es un string que define el nombre de nuestro proyecto (esto es a efectos para nuestra documentacion autogenerada)

Summary

Es un string donde podremos definir un breve resumen de la funcionalidad de la API, aparecerá en el endpoint “/docs”

Description

Un string donde podremos describir la API, esta soporta MarkDown

Version

Es un string que indicará la versión de la API en la documentación “/docs”

openapi_url

Es un string donde se almacena una url que apunta a los schemas de OpenAPI, por defecto tiene “/openapi.json”

si se deshabilita asignandole None, no habra ningun Squema de openapi y no se generará los endpoint “/docs” y “/redocs”

openapi_tags

Lista de etiquetas utilizadas por OpenAPI; estas son las mismas etiquetas que se pueden establecer en las operaciones de ruta, como por ejemplo:

  • @app.get("/usuarios/", tags=["usuarios"])
  • @app.get("/elementos/", tags=["elementos"])

El orden de las etiquetas se puede usar para especificar el orden mostrado en herramientas como Swagger UI, utilizada en la ruta automática /docs.

No es necesario especificar todas las etiquetas utilizadas.

Aquellas etiquetas que no se declaren PUEDEN organizarse de forma aleatoria o basada en la lógica de las herramientas. Cada nombre de etiqueta en la lista DEBE ser único.

El valor de cada elemento es un dict que contiene la siguiente estructura:

tags = [
    {
        "name": "str",
        "description": "str",
        "externalDocs": {
            "description": "str",
            "url": "https://ejemplo.com/docs/example"
        }
    },
]

para agregarlo al servicio quedaria asi

from fastapi import FastAPI
app = FastAPI(debug=False)
# Etiqueta "test" añadida a la ruta "/"
@app.get("/", tags=["etiqueta_test"])
async def hello_world():
    """
    Funcion asíncrona que retorna un diccionario.
    """
    return {"message": "Hello world!"}

y en docs se veria asi

imagen

servers

Una lista de diccionarios con información de conectividad a un servidor objetivo.

Lo utilizarías, por ejemplo, si tu aplicación se sirve desde diferentes dominios y deseas utilizar el mismo Swagger UI en el navegador para interactuar con cada uno de ellos (en lugar de tener múltiples pestañas del navegador abiertas). O si deseas fijar las posibles URL.

Si la lista de servidores no se proporciona o está vacía, el valor predeterminado sería un diccionario con un valor url de /.

Cada elemento en la lista es un diccionario que contiene:

  • url: Una URL al host objetivo. Esta URL admite variables de servidor y PUEDE ser relativa, para indicar que la ubicación del host es relativa a donde se está sirviendo el documento OpenAPI. Se realizarán sustituciones de variables cuando una variable se mencione entre {llaves}.
  • description: Una cadena opcional que describe el host designado por la URL. Se PUEDE utilizar la sintaxis de CommonMark para una representación de texto enriquecido.
  • variables: Un diccionario entre el nombre de una variable y su valor. El valor se utiliza para la sustitución en la plantilla de URL del servidor.

Lee más en la documentación de FastAPI para trabajar detrás de un proxy.

un ejemplo seria

from fastapi import FastAPI
app = FastAPI(
    servers=[
        {
          "url": "https://stag.example.com", 
          "description": "Staging environment"},
        {
          "url": "https://prod.example.com",
          "description": "Production environment"
        },
    ]
)

imagen

dependencies

Una lista de dependencias globales, que se aplicarán a cada operación de ruta, incluso en subrutas.

Más información al respecto en la documentación de FastAPI para Dependencias Globales.

Ejemplo:

from fastapi import Depends, FastAPI
from .dependencies import func_dep_1, func_dep_2
app = FastAPI(dependencies=[Depends(func_dep_1), Depends(func_dep_2)])

esto hara que la func_dep_1 y func_dep_2 se ejecuten siempre al inicio de un llamado en todas las rutas que registremos

default_response_class

Aqui podemos sobreescribir la clase de respuesta por defecto que tiene FastAPI, podemos crear la propia nuestra o usar otras que ya provee el mismo Framework

Ejemplo

from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
app = FastAPI(default_response_class=ORJSONResponse)

redirect_slashes

Determina si se deben detectar y redirigir las barras diagonales en las URL cuando el cliente no utiliza el mismo formato.

Ejemplo

from fastapi import FastAPI
app = FastAPI(redirect_slashes=True)  # el valor predeterminado
@app.get("/items/")
async def read_items():
    return [{"item_id": "Foo"}]

Con esta aplicación, si un cliente va a /items (sin una barra diagonal al final), será redirigido automáticamente con un código de estado HTTP 307 a /items/.

docs_url

La ruta a la documentación automática e interactiva de la API. Esta se maneja en el navegador mediante Swagger UI.

La URL predeterminada es /docs. Puedes desactivarla estableciéndola como None.

Si openapi_url se establece como None, esto se desactivará automáticamente.

Lee más en la documentación de FastAPI para URL de Metadata y Documentación.

from fastapi import FastAPI
app = FastAPI(docs_url="/documentacion")

En este ejemplo, se configura la aplicación FastAPI para tener la documentación en la URL /documentacion

redoc_url

La ruta a la documentación alternativa, automática e interactiva de la API proporcionada por ReDoc.

La URL predeterminada es /redoc. Puedes desactivarla estableciéndola como None.

Si openapi_url se establece como None, esto se desactivará automáticamente.

Lee más en la documentación de FastAPI para URL de Metadata y Documentación.

from fastapi import FastAPI
app = FastAPI(docs_url="/documentacion", redoc_url="redocumentacion")

En este ejemplo, se configura la aplicación FastAPI para tener la documentación alternativa en la URL /documentacion proporcionada por ReDoc, y se personaliza la ruta a /redocumentacion.

middleware

Lista de middleware que se añadirán al crear la aplicación.

En FastAPI, normalmente harías esto con app.add_middleware() en su lugar.

Lee más en la documentación de FastAPI para Middleware.

exception_handlers

Un diccionario con manejadores para excepciones.

En FastAPI, normalmente utilizarías el decorador @app.exception_handler().

Lee más en la documentación de FastAPI para Manejo de Errores.

terms_of_service

Una URL a los Términos de Servicio para tu API.

Se añadirá a la OpenAPI generada (por ejemplo, visible en /docs).

Lee más en la documentación de FastAPI para URL de Metadata y Documentación.

app = FastAPI(terms_of_service="http://example.com/terms/")

contact

Un diccionario con la información de contacto para la API expuesta.

Puede contener varios campos.

  • name: (str) El nombre de la persona/organización de contacto.
  • url: (str) Una URL que apunta a la información de contacto. DEBE estar en el formato de una URL.
  • email: (str) La dirección de correo electrónico de la persona/organización de contacto. DEBE estar en el formato de una dirección de correo electrónico.

Se añadirá a la OpenAPI generada (por ejemplo, visible en /docs).

Lee más en la documentación de FastAPI para URL de Metadata y Documentación.

app = FastAPI(
    contact={
        "name": "company or username",
        "url": "http://yourwebpage.com/contact/",
        "email": "contact@example.com",
    }
)

En este ejemplo, se configura la aplicación FastAPI con información de contacto, incluyendo el nombre, una URL y una dirección de correo electrónico. Esta información se reflejará en la documentación generada.

license_info

Un diccionario con la información de la licencia para la API expuesta.

Puede contener varios campos.

  • name: (str) REQUERIDO (si se establece license_info). El nombre de la licencia utilizada para la API.
  • identifier: (str) Una expresión de licencia SPDX para la API. El campo identifier es mutuamente exclusivo con el campo url. Disponible desde OpenAPI 3.1.0, FastAPI 0.99.0.
  • url: (str) Una URL a la licencia utilizada para la API. DEBE estar en el formato de una URL.

Se añadirá a la OpenAPI generada (por ejemplo, visible en /docs).

Lee más en la documentación de FastAPI para URL de Metadata y Documentación.

app = FastAPI(
    license_info={
        "name": "Apache 2.0",
        "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
    }
)

En este ejemplo, se configura la aplicación FastAPI con información de la licencia, incluyendo el nombre y una URL a la licencia. Esta información se reflejará en la documentación generada.

**extra

Argumentos clave adicionales para ser almacenados en la aplicación, no utilizados por FastAPI en ninguna parte.

Este es un espacio para que puedas almacenar información adicional específica de tu aplicación en la instancia de la aplicación (app). FastAPI no utilizará estos argumentos, pero puedes utilizarlos para cualquier propósito específico de tu aplicación.

from fastapi import FastAPI
extra_args = {
    "custom_setting_1": "value_1",
    "custom_setting_2": "value_2",
}
app = FastAPI(**extra_args)215103

Resumen

En este capitulo pudimos dar un ejemplo muy básico de como instalar, y desplegar una aplicación con FastAPI, además de entregar información detallada del constructor de la clase, pero eso no es todo lo que puede ofrecer FastAPI y para ello debemos poner a prueba los decoradres y modulos externos que nos puede ofrecer.

en el próximo capitulo aprenderemos a hacer un CRUD con FastAPI para poder usar definir endpoints con más metodos y estrucutras que ofrece el protocolo Http.

Seguí leyendo