Copiar enlace

En este tutorial crearemos un proyecto web FullStack usando Python en el backend junto a su Framework llamado FastAPI y a Javascript en el frontend junto a su Framework llamado React. Ademas que tambien usaremos una base de datos como lo es Mongodb.

Requerimientos

Antes de hacer este tutorial es esencial contar con las siguientes bases:

  • Conocer las bases de Python
  • Tener Mongodb instalado
  • FastAPI, saber que es FastAPI

creacion del proyecto

python -m venv venv

Active el entorno virtual o si estas usando VSCode simplemente selecciona la carpeta venv

pip install fastapi uvicorn motor

Incialización del servidor

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "http://localhost:5173",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")	
def welcome():
    return {"message": "Welcome to the API!"}
uvicorn main:app --reload

Añade estas rutas

@app.get('/api/tasks')
async def get_tasks():
    return {"data": "All tasks"}

@app.get('/api/tasks/{id}')
async def get_task(id: int):
    return {"data": id}

@app.post('/api/tasks')
async def create_task():
    return {"data": "Task created"}

@app.put('/api/tasks/{id}')
async def update_task(id: int, data):
    return {"data": f"Task {id} has been updated"}

@app.delete('/api/tasks/{id}')
async def delete_task(id: int):
    return {"data": f"Task {id} has been deleted"}

Puedes ver estas rutas si vas en /docs

Mongodb Queries

Luego de crear las rutas vamos a crear una conexion con Mongodb y vamos a definir las rutas que necesitamos crear, en un archivo llamado database.py

async def get_one_task(id):
    task = await collection.find_one({"_id": id})
    return task

Luego tambien vamos a crear un archivo Models:

from typing import Optional
from pydantic import BaseModel, Field
from bson import ObjectId


class PyObjectId(ObjectId):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if not ObjectId.is_valid(v):
            raise ValueError('Invalid ObjectId')
        return str(v)


class Task(BaseModel):
    id: Optional[PyObjectId] = Field(alias='_id')
    title: str
    description: str
    completed: bool = False

    class Config:
        orm_mode = True
        allow_population_by_field_name = True
        json_encoders = {
            ObjectId: str
        }


class UpdateTask(BaseModel):
    title: Optional[str] = None
    description: Optional[str] = None
    completed: Optional[bool] = None

Actualizacion de Rutas

Una vez tengamos los modelos y las consultas de Mongodb podemos actualizar nuestras rutas de esta forma:

@app.get("/")	
def welcome():
    return {"message": "Welcome to the API!"}

@app.get('/api/tasks')
async def get_tasks():
    response = await get_all_tasks()
    return response

@app.get('/api/tasks/{id}', response_model=Task)
async def get_task(id: int):
    response = await get_one_task(id)
    if response:
        return response
    raise HTTPException(404, f"There is no task with the id {id}")


@app.post('/api/tasks', response_model=Task)
async def save_task(task: Task):
    taskFound = await get_one_task(task.title)
    if taskFound:
        raise HTTPException(409, "Task already exists")

    response = await create_task(task.dict())
    print(response)
    if response:
        return response
    raise HTTPException(400, "Something went wrong")

@app.put('/api/tasks/{id}', response_model=Task)
async def put_task(id: int, data):
    response = await update_task(id, data)
    if response:
        return response
    raise HTTPException(404, f"There is no task with the id {id}")
    

@app.delete('/api/tasks/{id}')
async def remove_task(id: int):
    response = await delete_task(id)
    if response:
        return "Successfully deleted task"
    raise HTTPException(404, f"There is no task with the id {id}")

Separacion de Rutas

Una vez creadas la rutas es buena idea separarlas en su propio archivo, debido a que luego podamos necesitar crear mas rutas o endpoints.

Crea una carpeta llamada routes en la raiz del proyecto y dentro un archivo llamado task.py con el siguiente código:

@app.get("/")	
def welcome():
    return {"message": "Welcome to the API!"}

@app.get('/api/tasks')
async def get_tasks():
    response = await get_all_tasks()
    return response

@app.get('/api/tasks/{id}', response_model=Task)
async def get_task(id: int):
    response = await get_one_task(id)
    if response:
        return response
    raise HTTPException(404, f"There is no task with the id {id}")


@app.post('/api/tasks', response_model=Task)
async def save_task(task: Task):
    taskFound = await get_one_task(task.title)
    if taskFound:
        raise HTTPException(409, "Task already exists")

    response = await create_task(task.dict())
    print(response)
    if response:
        return response
    raise HTTPException(400, "Something went wrong")

@app.put('/api/tasks/{id}', response_model=Task)
async def put_task(id: int, data):
    response = await update_task(id, data)
    if response:
        return response
    raise HTTPException(404, f"There is no task with the id {id}")
    

@app.delete('/api/tasks/{id}')
async def remove_task(id: int):
    response = await delete_task(id)
    if response:
        return "Successfully deleted task"
    raise HTTPException(404, f"There is no task with the id {id}")

Luego en cuanto al archivo main.py, actualicemoslo de esta forma:

Despliegue

Para desplegar este proyecto en Railway, vamos a tener que considerar que tenemos dos aplicaciones, pero ambas estan en un mismo repositorio de Git, lo que significa que tenemos un monorepo, asi que para desplegarlo railway nos permite especifica que carpeta dentro del repositorio queremos desplegar y cada uno ira con su propio archivo de configuracion de railway, en donde una puede usar Nodejs, y la otra Python, y ejecutando indpendientemente sus modulos y comandos.

Los pasos que hare son:

  1. Crear una base de datos de Mongodb en Producción
  2. Configurar y desplegar Backend
  3. Configurar y desplegar Frontend
  4. Actualizar variables de entorno
pip freeze > requirements.txt

añade railway.json en la raiz de tu carpeta backend:

{
    "$schema": "https://railway.app/railway.schema.json",
    "build": {
        "builder": "NIXPACKS"
    },
    "deploy": {
        "startCommand": "uvicorn main:app --host 0.0.0.0 --port $PORT",
        "restartPolicyType": "ON_FAILURE",
        "restartPolicyMaxRetries": 10
    }
}

Luego en Railway, tenemos que establecer las variables de entorno de nuestra aplicacion de backend:

FRONTEND_URL=http://localhost:5173
MONGO_URL=${{MongoDB.MONGO_URL}}

ve en railway.com

Tambien este es una plantilla de ejemplo de que configuración añadir: https://github.com/railwayapp-templates/fastapi

En cuanto al Frontend

Para desplegar el frontend, solo tenemos que crear un servidor HTTP:

npm i serve

Y luego añadir esta configuracion en nuestro package.json:

    "start": "serve build -s -n -L -p $PORT",

Tambien recuerda que el Frontend es necesario que sepa a donde pedir datos, por lo que tambien tenemos que configurar su variable de entorno:

VITE_APP=http://railwaybackendurl.com

Tambien tenemos una plantilla de ejemplo de configuración

Más Recursos

Actualizado por ultima vez el

Desarrolla aplicacion fullstack usando Python y Javascript usando frameworks como FastAPI y React, ademas de Mongodb como base de datos

¿Quieres Compatir mi Contenido?

Publicado:hace 4 años

Actualizado:hace 2 años