Cómo instalar Fast API con MongoDB en Ubuntu 24.04

FastAPI es un framework web basado en Python para crear servicios API. Es un framework moderno, rápido y de alto rendimiento que soporta operaciones asíncronas.

En este tutorial, aprenderás a instalar FastAPI con MongoDB en Ubuntu 24.04. También aprenderás a crear tu primera API con operaciones CRUD utilizando FastAPI y la base de datos MongoDB.

Requisitos previos

Para empezar con esta guía, asegúrate de que tienes lo siguiente:

  • Un sistema Ubuntu 24.04
  • Un usuario no root con privilegios de administrador

Instalación de MongoDB

Antes de crear un nuevo proyecto FastAPI, vamos a instalar el servidor MongoDB en nuestro sistema.

En primer lugar, ejecuta el siguiente comando para actualizar tu índice de paquetes e instalar ‘gnupg’ y ‘curl’ en tu sistema.

sudo apt update && sudo apt install gnupg curl -y

Ejecuta el siguiente comando para añadir la clave GPG para el servidor MongoDB.

curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor

Añade el repositorio MongoDB utilizando el comando que aparece a continuación.

echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list

Una vez añadido el repositorio, ejecuta el siguiente comando para actualizar tu índice de paquetes e instalar el servidor MongoDB. Introduce «Y» para confirmar la instalación.

sudo apt update && sudo apt install mongodb-org

añadir repo

Una vez finalizada la instalación, inicia y habilita el servicio MongoDB ‘mongod’ y, a continuación, comprueba el estado de tu servicio MongoDB para asegurarte de que se está ejecutando.

sudo systemctl enable --now mongod
sudo systemctl status mongod

A continuación puedes ver que el servidor MongoDB se está ejecutando.

iniciar activar y verificar

Además, puedes iniciar sesión en el servidor MongoDB con el comando ‘mongosh’ que aparece a continuación. Para salir, pulsa Ctrl+d.

mongosh

Configurar Python y el entorno virtual

Con MongoDB instalado, instalarás los paquetes de Python y configurarás el directorio del proyecto y el entorno virtual.

Instala los módulos Python, Pip y Venv con el siguiente comando. Introduce ‘Y’ para confirmar la instalación.

sudo apt install python3 python3-pip python3-venv

instalar paquetes python

Una vez finalizada la instalación, inicia sesión con tu usuario.

su - username

Ahora crea un nuevo directorio‘~/app‘ y entra en él. Este directorio se utilizará para almacenar tu proyecto FastAPI.

mkdir -p ~/app; cd ~/app

Ejecuta el siguiente comando para crear un nuevo entorno virtual‘venv‘ y actívalo. De este modo, tu intérprete de comandos será como ‘(venv) usuario@nombrehost‘.

python3 -m venv .venv
source .venv/bin/activate

configuración venv

A partir de aquí, tu entorno de trabajo debe estar en el entorno virtual ‘venv’. Puedes cerrar la sesión en «venv» utilizando el siguiente comando.

deactivate

Creación del proyecto FastAPI

Ahora que has creado y activado tu entorno virtual Python, vamos a instalar FastAPI y a crear la estructura del proyecto.

Ejecuta el comando ‘pip3’ para instalar los paquetes ‘fastapi’ y ‘uvicorn’.

pip3 install fastapi uvicorn
  • El ‘fastapi’ es el principal framework web FastAPI para construir APIs en Python
  • El ‘uvicorn’ es la implementación del servidor web ASGI (Asynchronous Server Gateway Interface) en Python.

Una vez finalizada la instalación, crea nuevos archivos y directorios con el siguiente comando.

mkdir -p server/{models,routes}
touch main.py server/{app.py,database.py} server/models/itemModels.py server/routes/item.py

A continuación se muestra la estructura de nuestro proyecto FastAPI.

estructuras

servidor/app.py

Ahora que tu proyecto está listo, vamos a modificar el archivo ‘server/app.py’, que es la aplicación principal de tu proyecto FastAPI.

Abre el archivo‘app.py‘ con tu editor de texto y copia el siguiente script.

from fastapi import FastAPI
app = FastAPI()

@app.get("/")
async def root():
return {"message": "Hello FastAPI!"}
  • Importa el módulo FastAPI a tu proyecto y vincúlalo a la variable ‘app
  • Crea una nueva función ‘raíz’ que devuelva el mensaje ‘¡Hola FastAPI!
  • La función ‘root’ responde al método GET de la URL raíz
  • async’ marca tu función como función asíncrona y puede utilizar ‘await’ dentro de su cuerpo cuando sea llamada

main.py

En esta sección, modificaremos el archivo ‘main.py’ que se utilizará para ejecutar tu proyecto FastAPI a través de ‘uvicorn’ (servidor web ASGI en Python).

Ahora abre y modifica el script‘main.py‘ e inserta el siguiente código.

import uvicorn
if __name__ == "__main__":
uvicorn.run("server.app:app", host="0.0.0.0", port=8080, reload=True)
  • Importar el módulo «uvicorn
  • Cuando se ejecute el script ‘main.py’, cargará el módulo ‘app’ o FastAPI dentro del ‘server/app.py’
  • FastAPI se ejecutará en «0.0.0.0» con el puerto «8080».
  • Activa la auto-recarga cuando cambie el código mediante ‘reload=True’

Ejecuta tu proyecto FastAPI

Ahora que tu proyecto está listo, vamos a ejecutar tu primer proyecto FastAPI.

Ejecuta el script ‘main.py’ como se indica a continuación y tu FastAPI estará funcionando en tu sistema.

python3 main.py

ejecuta fastapi

Ahora abre tu navegador web y visita http://SERVERIP:8080/. Si la instalación se ha realizado correctamente, verás el mensaje ‘¡Hola FastAPI! También puedes acceder a ella mediante ‘curl’ desde el terminal.

Por último, puedes acceder a la documentación de la API en http://SERVERIP:8080/docs> que proporciona Swagger UI.

fastapi docs

Conectar FastAPI a MongoDB

En esta guía, crearás una API básica con FastAPI y MongoDB. Tu API debe ser capaz de hacer CRUD con el servidor de base de datos MongoDB. En este paso, conectarás tu proyecto al servidor MongoDB.

En primer lugar, ejecuta el siguiente comando ‘pip3’ para instalar el controlador‘motor’ de MongoDB en tu proyecto. ‘motor’ proporciona un acceso API no bloqueante y basado en coroutinas al servidor MongoDB.

pip3 install motor

servidor/base de datos.py

Una vez instalado el módulo«motor«, vamos a modificar el script«server/database.py«.

Abre el archivo ‘server/database.py’ con tu editor de texto e introduce el siguiente script. Se utilizará para conectar con el servidor MongoDB a través del módulo «motor».

from motor.motor_asyncio import AsyncIOMotorClient
MONGODB_HOST = "mongodb://localhost:27017"

connection = AsyncIOMotorClient(MONGODB_HOST)

database = connection.items
item_collection = database.get_collection("item_collection")
  • Importa el ‘AsyncIOMotorClient’ del módulo ‘motor.motor_asyncio’.
  • Crea una nueva constante «MONGODB_HOST» y apunta al servidor MongoDB «mongodb://localhost:27017».
  • Conéctate al servidor MongoDB mediante la variable ‘connection
  • Conéctate a la base de datos ‘items’ mediante la variable ‘database
  • Accede a las colecciones de la base de datos con la variable ‘item_collection

Crear un modelo de base de datos con pydantic

En esta sección, diseñarás tus datos mediante‘pydantic‘, que proporciona modelado para nuestra base de datos MongoDB.

Instala el módulo ‘pydantic’ con el siguiente comando ‘pip3’. El módulo‘pydantic‘ es una biblioteca de validación de datos que te permite crear esquemas de bases de datos mediante modelos.

pip3 install pydantic

Ahora abre el archivo‘server/models/itemModels.py‘ con tu editor de texto y copia el siguiente script.

from pydantic import BaseModel, Field
from typing import Optional
class Item(BaseModel):
name: str
category: str
stocks: int
price: int = Field(gt=0)

class Config:
json_schema_extra = {
"example": {
"name": "Company Smart Watch",
"category": "smartwatch",
"stocks": 10,
"price": 1000,
}
}

class ItemUpdate(BaseModel):
name: Optional[str] = None
category: Optional[str] = None
stocks: Optional[int] = None
price: Optional[int] = None

class Config:
json_schema_extra = {
"example": {
"name": "New Smart watch",
"category": "new-smartwatch",
"stocks": 5,
"price": 500,
}
}
  • Importa los módulos ‘BaseModel’ y ‘Field’ de ‘pydantic’.
  • Importa el módulo «Opcional» de «typing».
  • Crea el siguiente esquema de base de datos «Elemento» para la FastAPI:
    • ‘nombre’ y ‘categoría’ con tipo cadena
    • ‘existencias’ y ‘precio’ con categoría entero
    • ‘precio’ debe ser mayor que 0
  • Amplía el modelo de datos mediante la clase ‘Config’ proporcionando un ejemplo de datos que el usuario puede incluir en la solicitud
  • Crea el siguiente esquema ‘ItemUpdate’ con todos los campos como opcionales.

Añadir operaciones CRUD

Llegados a este punto, ya has creado una conexión con el servidor MongoDB y creado el esquema de la base de datos mediante ‘pydantic’. Pasemos a crear las operaciones CRUD con FastAPI y MongoDB.

Abre de nuevo el script‘server/database.py‘ y crea una nueva función‘item_helper‘ con tipo‘dict‘. Llama a esta función para obtener datos detallados sobre un elemento.

def item_helper(item) -> dict:
 return {
 "id": str(item["_id"]),
 "name": item["name"],
 "category": item["category"],
 "stocks": item["stocks"],
 "price": item["price"],
 }

Añade la siguiente línea para importar el módulo ‘ObjectId‘ de ‘bson.objectid’. El‘ObjectId‘ forma parte del tipo de datos en BSON, que MongoDB utiliza para el almacenamiento y representación de datos JSON.

from bson.objectid import ObjectId

Crear un elemento

En primer lugar, crearás una función asíncrona que podrá añadir nuevos datos a la base de datos MongoDB.

Crea una nueva función ‘add_item‘ como la siguiente:

# Add a new item
async def add_item(item_details: dict) -> dict :
 item = await item_collection.insert_one(item_details)
 new_item = await item_collection.find_one({"_id": item.inserted_id})
 return item_helper(new_item)
  • La función ‘add_item’ acepta datos de diccionario de los detalles de tu artículo
  • A través de ‘item_collection’ accede a los documentos de la base de datos y ejecuta la consulta ‘insert_one’ para añadir un nuevo elemento
  • El nuevo artículo se imprimirá si la operación se realiza correctamente

Recuperar todos los artículos

En segundo lugar, crearás una nueva función ‘get_items’ que podrá recuperar todos los elementos disponibles en tu base de datos.

Crea una nueva función‘get_items‘ para recuperar todos los elementos de MongoDB.

# retrieve all items
async def get_items():
 items = []
 async for item in item_collection.find():
 items.append(item_helper(item))
 return items
  • Crearás una lista vacía de ‘ítems’.
  • Utilizarás la consulta ‘find()’ para buscar todos los datos y hacer un bucle a través de ellos
  • Cada elemento se añadirá a la lista ‘items’ mediante el método ‘append
  • Una vez completado el bucle, se mostrarán tus elementos

Recuperar un elemento específico basado en el id

A continuación, crearás una nueva función que podrá recuperar datos para el selector específico «id». Esto te mostrará datos detallados sobre artículos específicos.

Crea una nueva función‘get_item‘ para recuperar datos de elementos específicos. La función ‘get_item’ aceptará una cadena de ‘id’ como selector y devolverá un diccionario.

# retrieve specific item
async def get_item(id: str) -> dict:
 item = await item_collection.find_one({"_id": ObjectId(id)})
 if item:
 return item_helper(item)
 return "Item Not Found."
  • La consulta ‘find_one()’ se utilizará para recuperar datos basados en el ‘id’
  • Si se encuentra un artículo, se mostrarán los detalles utilizando el formato de diccionario ‘item_helper
  • Si el artículo no está disponible, la respuesta será ‘Artículo no encontrado’.

Actualizar un artículo

Ahora crearás una nueva función para actualizar un ítem. También puedes actualizar parcialmente tu ítem a través de la API.

Define la nueva función‘cambiar_elemento‘ como los siguientes códigos:

# update item
async def change_item(id: str, data: dict):
 if len(data) < 1:
 return "Please input your data"
 find_item = await item_collection.find_one({"_id": ObjectId(id)})
 if find_item:
 item_update = await item_collection.update_one({"_id": ObjectId(id)}, {"$set": data})
 if item_update:
 return True
 return False
  • La función ‘change_item’ toma dos argumentos, el ‘id’ del elemento de destino y ‘data’ como los nuevos datos
  • Si los datos están vacíos o son ‘< 1’, la operación finaliza
  • Esta función buscará un elemento basándose en el selector «id
  • Si se encuentra el ‘id’, se ejecutará ‘item_update
  • Si el ‘item_update’ tiene éxito, devuelve ‘True’, o devuelve ‘False’ en caso contrario

Eliminar un elemento

Por último, crearemos la función ‘eliminar_elemento’ para eliminar elementos mediante un selector específico.

Para eliminar un elemento, crearemos la función«eliminar_elemento» y utilizaremos el selector «id» como se indica a continuación:

# delete an item
async def delete_item(id: str):
 item = await item_collection.find_one({"_id": ObjectId(id)})
 if item:
 await item_collection.delete_one({"_id": ObjectId(id)})
 return(f'Item {id} deleted.')
 return "Item Not Found."
  • La consulta ‘find_one()’ buscará un elemento basándose en el ‘id’ proporcionado
  • Si se encuentra el elemento, se eliminará mediante la consulta ‘delete_one()’ y devolverá el ‘Id de elemento eliminado’
  • Si el elemento no está disponible, se mostrará el mensaje «Elemento no encontrado».

Añadir rutas para operaciones CRUD

Llegados a este punto, hemos creado funciones asíncronas para operaciones CRUD con FastAPI. Ahora vamos a crear la ruta o endpoint para cada operación.

Edita el archivo‘server/routes/item.py‘ utilizando tu editor preferido.

servidor/rutas/elemento.py

Primero, añade los módulos ‘APIRouter‘ y‘Body’ de ‘fastapi’. A continuación, añade el módulo‘jsonable_encode‘ de ‘fastapi.encoders’.

from fastapi import APIRouter, Body
from fastapi.encoders import jsonable_encoder

Importa cada función del archivo ‘database.py’.

from server.database import (
 add_item,
 get_items,
 get_item,
 change_item,
 delete_item,
)

Importa los modelos ‘Item’ y ‘ItemUpdate’ del archivo ‘itemModels.py’.

from server.models.itemModels import (
 Item,
 ItemUpdate,
)

Llama a la clase ‘APIRouter’ a través de la variable ‘router’.

router = APIRouter()

Ruta para añadir un nuevo artículo

Ahora vamos a añadir una ruta para añadir nuevos artículos. En este ejemplo, puedes añadir un nuevo elemento mediante POST a la URL‘/item‘.

Añade las siguientes líneas para configurar las rutas para añadir nuevos elementos. Cada POST a la URL raíz del elemento se tratará como inserción de nuevos datos.

# add new item operation
@router.post("/")
async def add_item_data(item: Item = Body(...)):
 item = jsonable_encoder(item)
 new_item = await add_item(item)
 return new_item
  • La función ‘add_item_data’ acepta el esquema ‘Artículo’, que formará parte del ‘Cuerpo’ de tu petición
  • Tu ítem se convertirá a formato diccionario mediante ‘jsonable_encoder’
  • Inserta tus datos de diccionario mediante la función ‘add_item’ (ver base_de_datos.py) sobre la variable ‘new_item
  • Devuelve tus datos insertados ‘nuevo_elemento’ como respuesta

Ruta para obtener todos los elementos

Añade el siguiente script para configurar una ruta para recuperar datos. Cada petición GET a la URL raíz del elemento recuperará todos tus datos.

# get all available items
@router.get("/")
async def get_item_data():
 items = await get_items()
 if items:
 return items
 return "No available item."
  • Crea la función ‘get_item_data’ que ejecutará la función ‘get_item’ del archivo ‘database.py
  • Si hay artículos disponibles, obtendrás la lista de todos tus artículos
  • Si no hay ningún artículo, obtendrás la respuesta «Ningún artículo disponible

Ruta para obtener un artículo concreto

Para obtener los detalles de un artículo concreto, utilizaremos el «id» como selector. Cada solicitud GET al ‘/id’ devolverá un artículo detallado del ‘id’ solicitado.

# Show details of the item via the id
@router.get("/{id}")
async def get_item_details(id):
 item_details = await get_item(id)
 if item_details:
 return item_details
 return "Item not found."
  • Se creará la función ‘get_item_details’ y se le pasará el ‘id’ de la URL
  • Se llamará a la función ‘get_item’ (ver base de datos.py) y también se le pasará el ‘id’ como argumento
  • Si se encuentra el artículo, se mostrarán los detalles del mismo
  • Si no hay ningún artículo con ese ‘id’ específico, obtendrás ‘Artículo no encontrado’

Ruta para actualizar un artículo

Copia el siguiente código para establecer la ruta para el elemento actualizado:

# Update Item
@router.put("/{id}")
async def update_item(id: str, data: ItemUpdate = Body(...)):
 data = {k: v for k, v in data.dict().items() if v is not None}
 updated_item = await change_item(id, data)
 if updated_item:
 return{f'Success: item {id} updated.'}
 return "Error"
  • La función ‘update_item’ tomará dos argumentos, ‘id’ como selector y los ‘datos’, que se basan en el modelo ‘ItemUpdate
  • Los datos se comprobarán en la variable ‘datos
  • El ‘elemento_actualizado’ ejecutará la función ‘cambiar_elemento’ del archivo ‘base_de_datos.py
  • Si la actualización tiene éxito, verás la salida ‘Éxito

Ruta para eliminar un elemento

Inserta las siguientes líneas para crear la función ‘eliminar_elemento’ para borrar elementos. Cada operación DELETE a un ‘/id’ específico, eliminará el elemento coincidente con el ‘id’.

# delete item via id
@router.delete("/{id}")
async def remove_item(id):
 item_to_delete = await delete_item(id)
 if item_to_delete:
 return item_to_delete
 return{f'Item {id} Not Available.'}
  • La función ‘eliminar_elemento’ ejecutará ‘eliminar_elemento’ y pasará el selector ‘id’.
  • La operación de eliminación se almacenará y ejecutará a través de la variable ‘item_to_delete
  • Cuando un elemento no esté disponible, obtendrás el retorno ‘Id de elemento no disponible’

servidor/app.py

Ahora que has terminado el archivo ‘servidor/rutas/artículo.py’, vamos a incluirlo en el archivo ‘servidor/app.py’.

Abre el archivo‘app.py‘ con tu editor de texto.

Importa el ‘enrutador’ del archivo‘servidor/rutas/elemento.py‘ como un‘ItemRouter‘.

from server.routes.item import router as ItemRouter

Inserta el ‘ItemRouter’ con el prefijo por defecto‘/item‘. Las operaciones CRUD se gestionarán a través de la URL‘/item‘.

app.include_router(ItemRouter, tags=["Item"], prefix="/item")

Ahora tu punto final CRUD estará disponible en lo siguiente:

  • Añadir nuevo elemento: POST a‘/artículo
  • Recuperar todos los elementos: GET a‘/artículo
  • Recuperar un elemento específico: GET a ‘/artículo/id’. El ‘id’ lo genera MongoDB
  • Actualizar un elemento: PUT a ‘/artículo/id’
  • Eliminar elemento: DELETE a ‘/artículo/id’

Prueba las operaciones CRUD

En primer lugar, asegúrate de que tu proyecto FastAPI se está ejecutando, o puedes ejecutar el script ‘main.py’ como el siguiente:

python3 main.py

Navega por http://SERVERIP:8080/docs y verás cada ruta que hayas creado.

Operaciones CRUD

A continuación se muestra un ejemplo de adición de un nuevo elemento.

añadir nuevo elemento

Recuperar todos los elementos disponibles a través de la API.

recuperar elemento todos

Recuperar elementos específicos mediante el selector «id».

recuperar un elemento específico

Actualizar datos parciales de elementos específicos.

actualizar elemento

A continuación se muestran los datos actualizados.

datos actualizados

A continuación se muestra la operación de eliminación mediante el selector «id».

borrar datos

Conclusión

¡Enhorabuena! Has completado la instalación de FastAPI con MongoDB en Ubuntu 24.04. También has aprendido a conectar FastAPI a MongoDB mediante el módulo ‘motor’, a crear modelos de datos mediante ‘pydantic’, a crear operaciones CRUD con FastAPI y a crear endpoints para tu API.

También te podría gustar...