Skip to content

[pull] main from mouredev:main #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Aug 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Backend/FastAPI/db/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,10 @@
# "mongodb+srv://<user>:<password>@<url>/?retryWrites=true&w=majority").test

# Despliegue API en la nube:
# Deta - https://www.deta.sh/
# Intrucciones - https://fastapi.tiangolo.com/deployment/deta/
# Deta (deprecado) - https://www.deta.sh/
# Vercel - https://www.vercel.com
# Instrucciones - https://cleverzone.medium.com/fastapi-deployment-into-vercel-0fa4e6478014
# MUY IMPORTANTE - Al desplegar en producción, preparar el proyecto para trabajar con variables de entorno que hagan referencia a datos sensibles:
# - Nunca subas a un repositorio público el valor de las variables
# - Puedes usar dotenv en Python
# - Añade el valor de las variables desde el proveedor de hosting
2 changes: 1 addition & 1 deletion Backend/FastAPI/db/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@


class User(BaseModel):
id: Optional[str]
id: Optional[str] = None
username: str
email: str
1 change: 1 addition & 0 deletions Backend/FastAPI/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from fastapi import FastAPI
from routers import products, users, basic_auth_users, jwt_auth_users, users_db
from fastapi.staticfiles import StaticFiles
import os

app = FastAPI()

Expand Down
1 change: 1 addition & 0 deletions Backend/FastAPI/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=27335
fastapi
uvicorn
python-jose
passlib
bcrypt
Expand Down
12 changes: 7 additions & 5 deletions Backend/FastAPI/routers/basic_auth_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
from pydantic import BaseModel
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm

router = APIRouter(prefix="/basicauth",
tags=["basicauth"],
responses={status.HTTP_404_NOT_FOUND: {"message": "No encontrado"}})
router = APIRouter(
prefix="/basicauth",
tags=["basicauth"],
responses={status.HTTP_404_NOT_FOUND: {"message": "No encontrado"}}
)

oauth2 = OAuth2PasswordBearer(tokenUrl="login")

Expand All @@ -28,14 +30,14 @@ class UserDB(User):
"mouredev": {
"username": "mouredev",
"full_name": "Brais Moure",
"email": "braismoure@mourede.com",
"email": "braismoure@mouredev.com",
"disabled": False,
"password": "123456"
},
"mouredev2": {
"username": "mouredev2",
"full_name": "Brais Moure 2",
"email": "braismoure2@mourede.com",
"email": "braismoure2@mouredev.com",
"disabled": True,
"password": "654321"
}
Expand Down
16 changes: 9 additions & 7 deletions Backend/FastAPI/routers/jwt_auth_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import jwt, JWTError
from passlib.context import CryptContext
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone

ALGORITHM = "HS256"
ACCESS_TOKEN_DURATION = 1
SECRET = "201d573bd7d1344d3a3bfce1550b69102fd11be3db6d379508b6cccc58ea230b"

router = APIRouter(prefix="/jwtauth",
tags=["jwtauth"],
responses={status.HTTP_404_NOT_FOUND: {"message": "No encontrado"}})
router = APIRouter(
prefix="/jwtauth",
tags=["jwtauth"],
responses={status.HTTP_404_NOT_FOUND: {"message": "No encontrado"}}
)

oauth2 = OAuth2PasswordBearer(tokenUrl="login")

Expand All @@ -37,14 +39,14 @@ class UserDB(User):
"mouredev": {
"username": "mouredev",
"full_name": "Brais Moure",
"email": "braismoure@mourede.com",
"email": "braismoure@mouredev.com",
"disabled": False,
"password": "$2a$12$B2Gq.Dps1WYf2t57eiIKjO4DXC3IUMUXISJF62bSRiFfqMdOI2Xa6"
},
"mouredev2": {
"username": "mouredev2",
"full_name": "Brais Moure 2",
"email": "braismoure2@mourede.com",
"email": "braismoure2@mouredev.com",
"disabled": True,
"password": "$2a$12$SduE7dE.i3/ygwd0Kol8bOFvEABaoOOlC8JsCSr6wpwB4zl5STU4S"
}
Expand Down Expand Up @@ -103,7 +105,7 @@ async def login(form: OAuth2PasswordRequestForm = Depends()):
status_code=status.HTTP_400_BAD_REQUEST, detail="La contraseña no es correcta")

access_token = {"sub": user.username,
"exp": datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_DURATION)}
"exp": datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_DURATION)}

return {"access_token": jwt.encode(access_token, SECRET, algorithm=ALGORITHM), "token_type": "bearer"}

Expand Down
11 changes: 6 additions & 5 deletions Backend/FastAPI/routers/products.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@

from fastapi import APIRouter

router = APIRouter(prefix="/products",
tags=["products"],
responses={404: {"message": "No encontrado"}})
router = APIRouter(
prefix="/products",
tags=["products"],
responses={404: {"message": "No encontrado"}}
)

products_list = ["Producto 1", "Producto 2",
"Producto 3", "Producto 4", "Producto 5"]
products_list = ["Producto 1", "Producto 2", "Producto 3", "Producto 4", "Producto 5"]


@router.get("/")
Expand Down
7 changes: 4 additions & 3 deletions Backend/FastAPI/routers/users_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
from db.client import db_client
from bson import ObjectId

router = APIRouter(prefix="/userdb",
tags=["userdb"],
responses={status.HTTP_404_NOT_FOUND: {"message": "No encontrado"}})
router = APIRouter(
prefix="/userdb",
tags=["userdb"],
responses={status.HTTP_404_NOT_FOUND: {"message": "No encontrado"}})


@router.get("/", response_model=list[User])
Expand Down
14 changes: 14 additions & 0 deletions Backend/FastAPI/vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"builds": [
{
"src": "main.py",
"use": "@vercel/python"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "main.py"
}
]
}
134 changes: 65 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,8 @@
![](./Images/header.jpg)

### Proyecto realizado durante emisiones en directo desde [Twitch](https://twitch.tv/mouredev)
> ##### Si consideras útil el curso, apóyalo haciendo "★ Star" en el repositorio. ¡Gracias!

## ¡NUEVO! Curso de Python para web

[![Curso Python Web](https://img.shields.io/github/stars/mouredev/python-web?label=Curso%20Python%20web&style=social)](https://github.com/mouredev/python-web)

<a href="https://github.com/mouredev/python-web"><img src="https://raw.githubusercontent.com/mouredev/python-web/main/Images/header.jpg"/></a>
> ##### Si consideras útil el curso, apóyalo haciendo "★ Star" en el repositorio. ¡Gracias!

## Clases en vídeo

Expand All @@ -29,44 +24,44 @@ Curso que agrupa todas las clases en directo que hacen referencia a los fundamen

<a href="https://youtu.be/Kp4Mvapo5kc"><img src="http://i3.ytimg.com/vi/Kp4Mvapo5kc/maxresdefault.jpg" style="height: 50%; width:50%;"/></a>

* [Introducción](https://youtu.be/Kp4Mvapo5kc)
* [Contexto](https://youtu.be/Kp4Mvapo5kc?t=244)
* [Lección 1 - Configuración](https://youtu.be/Kp4Mvapo5kc?t=850)
* [Lección 2 - Hola Mundo](https://youtu.be/Kp4Mvapo5kc?t=1518)
* [Lección 3 - Variables](https://youtu.be/Kp4Mvapo5kc?t=2938)
* [Lección 4 - Operadores](https://youtu.be/Kp4Mvapo5kc?t=5665)
* [Lección 5 - Strings](https://youtu.be/Kp4Mvapo5kc?t=8643)
* [Lección 6 - Listas](https://youtu.be/Kp4Mvapo5kc?t=10872)
* [Lección 7 - Tuplas](https://youtu.be/Kp4Mvapo5kc?t=14711)
* [Lección 8 - Sets](https://youtu.be/Kp4Mvapo5kc?t=16335)
* [Lección 9 - Diccionarios](https://youtu.be/Kp4Mvapo5kc?t=18506)
* [Lección 10 - Condicionales](https://youtu.be/Kp4Mvapo5kc?t=21442)
* [Lección 11 - Bucles/Loops/Ciclos](https://youtu.be/Kp4Mvapo5kc?t=23822)
* [Lección 12 - Funciones](https://youtu.be/Kp4Mvapo5kc?t=26619)
* [Lección 13 - Clases](https://youtu.be/Kp4Mvapo5kc?t=29327)
* [Lección 14 - Excepciones](https://youtu.be/Kp4Mvapo5kc?t=32030)
* [Lección 15 - Módulos](https://youtu.be/Kp4Mvapo5kc?t=34583)
* [Próximos pasos](https://youtu.be/Kp4Mvapo5kc?t=36390)
- [Introducción](https://youtu.be/Kp4Mvapo5kc)
- [Contexto](https://youtu.be/Kp4Mvapo5kc?t=244)
- [Lección 1 - Configuración](https://youtu.be/Kp4Mvapo5kc?t=850)
- [Lección 2 - Hola Mundo](https://youtu.be/Kp4Mvapo5kc?t=1518)
- [Lección 3 - Variables](https://youtu.be/Kp4Mvapo5kc?t=2938)
- [Lección 4 - Operadores](https://youtu.be/Kp4Mvapo5kc?t=5665)
- [Lección 5 - Strings](https://youtu.be/Kp4Mvapo5kc?t=8643)
- [Lección 6 - Listas](https://youtu.be/Kp4Mvapo5kc?t=10872)
- [Lección 7 - Tuplas](https://youtu.be/Kp4Mvapo5kc?t=14711)
- [Lección 8 - Sets](https://youtu.be/Kp4Mvapo5kc?t=16335)
- [Lección 9 - Diccionarios](https://youtu.be/Kp4Mvapo5kc?t=18506)
- [Lección 10 - Condicionales](https://youtu.be/Kp4Mvapo5kc?t=21442)
- [Lección 11 - Bucles/Loops/Ciclos](https://youtu.be/Kp4Mvapo5kc?t=23822)
- [Lección 12 - Funciones](https://youtu.be/Kp4Mvapo5kc?t=26619)
- [Lección 13 - Clases](https://youtu.be/Kp4Mvapo5kc?t=29327)
- [Lección 14 - Excepciones](https://youtu.be/Kp4Mvapo5kc?t=32030)
- [Lección 15 - Módulos](https://youtu.be/Kp4Mvapo5kc?t=34583)
- [Próximos pasos](https://youtu.be/Kp4Mvapo5kc?t=36390)

### Curso intermedio de fundamentos desde cero

Curso en el que continuamos aprendiendo Python desde sus bases, siguiendo la ruta de aprendizaje desde la última lección del curso de inicial.

> Código: Directorio "Intermediate" en el proyecto

<a href="https://youtu.be/TbcEqkabAWU"><img src="http://i3.ytimg.com/vi/TbcEqkabAWU/maxresdefault.jpg" style="height: 50%; width:50%;"/></a>

* [Introducción](https://youtu.be/TbcEqkabAWU)
* [Lección 1 - Dates](https://youtu.be/TbcEqkabAWU?t=202)
* [Lección 2 - List Comprehension](https://youtu.be/TbcEqkabAWU?t=3239)
* [Lección 3 - Resolución de retos de programación](https://youtu.be/TbcEqkabAWU?t=4142)
* [Lección 4 - Lambdas](https://youtu.be/TbcEqkabAWU?t=9145)
* [Lección 5 - Funciones de orden superior](https://youtu.be/TbcEqkabAWU?t=10172)
* [Lección 6 - Tipos de error](https://youtu.be/TbcEqkabAWU?t=12721)
* [Lección 7 - Manejo de ficheros](https://youtu.be/TbcEqkabAWU?t=15524)
* [Lección 8 - Expresiones regulares](https://youtu.be/TbcEqkabAWU?t=19762)
* [Lección 9 - Manejo de paquetes](https://youtu.be/TbcEqkabAWU?t=24010)
* [Próximos pasos](https://youtu.be/TbcEqkabAWU?t=26228)
- [Introducción](https://youtu.be/TbcEqkabAWU)
- [Lección 1 - Dates](https://youtu.be/TbcEqkabAWU?t=202)
- [Lección 2 - List Comprehension](https://youtu.be/TbcEqkabAWU?t=3239)
- [Lección 3 - Resolución de retos de programación](https://youtu.be/TbcEqkabAWU?t=4142)
- [Lección 4 - Lambdas](https://youtu.be/TbcEqkabAWU?t=9145)
- [Lección 5 - Funciones de orden superior](https://youtu.be/TbcEqkabAWU?t=10172)
- [Lección 6 - Tipos de error](https://youtu.be/TbcEqkabAWU?t=12721)
- [Lección 7 - Manejo de ficheros](https://youtu.be/TbcEqkabAWU?t=15524)
- [Lección 8 - Expresiones regulares](https://youtu.be/TbcEqkabAWU?t=19762)
- [Lección 9 - Manejo de paquetes](https://youtu.be/TbcEqkabAWU?t=24010)
- [Próximos pasos](https://youtu.be/TbcEqkabAWU?t=26228)

### Backend desde cero

Expand All @@ -76,28 +71,28 @@ Curso en el que aprenderemos a utilizar Python para backend e implementaremos un

<a href="https://youtu.be/_y9qQZXE24A"><img src="http://i3.ytimg.com/vi/_y9qQZXE24A/maxresdefault.jpg" style="height: 50%; width:50%;"/></a>

* [Introducción](https://youtu.be/_y9qQZXE24A)
* [Lección 01 - ¿Qué es un backend?](https://youtu.be/_y9qQZXE24A?t=125)
* [Lección 02 - API y FastAPI](https://youtu.be/_y9qQZXE24A?t=834)
* [Lección 03 - Type Hints](https://youtu.be/_y9qQZXE24A?t=1810)
* [Lección 04 - Configuración FastAPI](https://youtu.be/_y9qQZXE24A?t=2629)
* [Lección 05 - Hola mundo](https://youtu.be/_y9qQZXE24A?t=3504)
* [Lección 06 - Operación GET](https://youtu.be/_y9qQZXE24A?t=5382)
* [Lección 07 - Peticiones HTTP](https://youtu.be/_y9qQZXE24A?t=5925)
* [Lección 08 - Creación API](https://youtu.be/_y9qQZXE24A?t=6099)
* [Lección 09 - Path y Query](https://youtu.be/_y9qQZXE24A?t=7510)
* [Lección 10 - Operaciones POST, PUT y DELETE](https://youtu.be/_y9qQZXE24A?t=8529)
* [Lección 11 - HTTP status codes](https://youtu.be/_y9qQZXE24A?t=11072)
* [Lección 12 - Routers](https://youtu.be/_y9qQZXE24A?t=12475)
* [Lección 13 - Recursos estáticos](https://youtu.be/_y9qQZXE24A?t=13618)
* [Lección 14 - Autorización OAuth2](https://youtu.be/_y9qQZXE24A?t=14094)
* [Lección 15 - OAuth2 JWT](https://youtu.be/_y9qQZXE24A?t=17664)
* [Lección 16 - MongoDB](https://youtu.be/_y9qQZXE24A?t=20480)
* [Lección 17 - MongoDB Atlas](https://youtu.be/_y9qQZXE24A?t=25470)
* [Lección 18 - Despliegue en Deta *](https://youtu.be/_y9qQZXE24A?t=27335)
* [Próximos pasos](https://youtu.be/_y9qQZXE24A?t=28484)

***ACTUALIZACIÓN Sobre la lección 18:** Deta ha actualizado ligeramente su servicio de despliegue de aplicaciones con FastAPI. Tienes toda la documentación [aquí](https://deta.space/docs/en/quickstart-guides/python#fastapi). También han creado una [guía de migración](https://deta.space/migration/guides/migrate-a-micro/).
- [Introducción](https://youtu.be/_y9qQZXE24A)
- [Lección 01 - ¿Qué es un backend?](https://youtu.be/_y9qQZXE24A?t=125)
- [Lección 02 - API y FastAPI](https://youtu.be/_y9qQZXE24A?t=834)
- [Lección 03 - Type Hints](https://youtu.be/_y9qQZXE24A?t=1810)
- [Lección 04 - Configuración FastAPI](https://youtu.be/_y9qQZXE24A?t=2629)
- [Lección 05 - Hola mundo](https://youtu.be/_y9qQZXE24A?t=3504)
- [Lección 06 - Operación GET](https://youtu.be/_y9qQZXE24A?t=5382)
- [Lección 07 - Peticiones HTTP](https://youtu.be/_y9qQZXE24A?t=5925)
- [Lección 08 - Creación API](https://youtu.be/_y9qQZXE24A?t=6099)
- [Lección 09 - Path y Query](https://youtu.be/_y9qQZXE24A?t=7510)
- [Lección 10 - Operaciones POST, PUT y DELETE](https://youtu.be/_y9qQZXE24A?t=8529)
- [Lección 11 - HTTP status codes](https://youtu.be/_y9qQZXE24A?t=11072)
- [Lección 12 - Routers](https://youtu.be/_y9qQZXE24A?t=12475)
- [Lección 13 - Recursos estáticos](https://youtu.be/_y9qQZXE24A?t=13618)
- [Lección 14 - Autorización OAuth2](https://youtu.be/_y9qQZXE24A?t=14094)
- [Lección 15 - OAuth2 JWT](https://youtu.be/_y9qQZXE24A?t=17664)
- [Lección 16 - MongoDB](https://youtu.be/_y9qQZXE24A?t=20480)
- [Lección 17 - MongoDB Atlas](https://youtu.be/_y9qQZXE24A?t=25470)
- [Lección 18 - Despliegue en Deta \*](https://youtu.be/_y9qQZXE24A?t=27335)
- [Próximos pasos](https://youtu.be/_y9qQZXE24A?t=28484)

**\*ACTUALIZACIÓN Sobre la lección 18:** Deta, el servicio utilizado para el despliegue durante el curso, ya no existe. Te recomiendo revisar la documentación oficial de FastAPI sobre [despliegue](https://fastapi.tiangolo.com/deployment/). Puedes utilizar alguno de los [proveedores gratuitos](https://fastapi.tiangolo.com/deployment/cloud/) recomendados. En mi caso, te dejo el [fichero de configuración](./Backend/FastAPI/vercel.json) y el de [dependencias](./Backend/FastAPI/requirements.txt) para hacerlo desde [Vercel](https://vercel.com/) (al crear el proyecto en la plataforma selecciona que el directorio "Backend/FastAPI" es el root).

### Frontend desde cero

Expand Down Expand Up @@ -146,21 +141,21 @@ Y para finalizar... ¿Quieres saber aun más sobre él? Aquí tienes 15 curiosid
Actualmente el curso está en pausa. Se han finalizados los bloques básico, intermedio y backend, y ese era el objetivo inicial del proyecto.
No descarto añadir nuevas lecciones a futuro, pero creo que por el momento puede servir de base a cualquier persona que quiera empezar a aprender este lenguaje.

* Recuerda que he creado en el [Discord](https://discord.gg/mouredev) un canal "🐍python" para que puedas comentar lo que quieras.
* En el momento que el curso continúe, actualizaré el repositorio y avisaré en redes.
- Recuerda que he creado en el [Discord](https://discord.gg/mouredev) un canal "🐍python" para que puedas comentar lo que quieras.
- En el momento que el curso continúe, actualizaré el repositorio y avisaré en redes.

¡Muchísimas gracias por todo el apoyo mostrado!

## Enlaces de interés

* [Web oficial de Python](https://www.python.org/)
* [Tutorial oficial de Python en Español](https://docs.python.org/es/3/tutorial/index.html)
* [Repo 30 días de Python](https://github.com/Asabeneh/30-Days-Of-Python)
* [Juego Codédex para aprender Python](https://www.codedex.io/)
* [Visual Studio Code](https://code.visualstudio.com/): El editor que estoy usando
* [FastAPI](https://fastapi.tiangolo.com/es/): El framework para crear nuestra API Backend
* [MongoDB](https://www.mongodb.com/): La base de datos que utiliza nuestro backend
* [Deta](https://www.deta.sh/): Para desplegar nuestra API en la nube
- [Web oficial de Python](https://www.python.org/)
- [Tutorial oficial de Python en Español](https://docs.python.org/es/3/tutorial/index.html)
- [Repo 30 días de Python](https://github.com/Asabeneh/30-Days-Of-Python)
- [Juego Codédex para aprender Python](https://www.codedex.io/)
- [Visual Studio Code](https://code.visualstudio.com/): El editor que estoy usando
- [FastAPI](https://fastapi.tiangolo.com/es/): El framework para crear nuestra API Backend
- [MongoDB](https://www.mongodb.com/): La base de datos que utiliza nuestro backend
- [Vercel](https://vercel.com/): Para desplegar nuestra API en la nube

## Únete al campus de programación de la comunidad

Expand All @@ -169,10 +164,11 @@ No descarto añadir nuevas lecciones a futuro, pero creo que por el momento pued
#### Te presento [mouredev pro](https://mouredev.pro), mi proyecto más importante para ayudarte a estudiar programación y desarrollo de software de manera diferente.

> **¿Buscas un extra?** Aquí encontrarás este y otros cursos editados por lecciones individuales, para avanzar a tu ritmo y guardar el progreso. También dispondrás de ejercicios y correcciones, test para validar tus conocimientos, examen y certificado público de finalización, soporte, foro de estudiantes, reunionnes grupales, cursos exclusivos y mucho más.
>
>
> Entra en **[mouredev.pro](https://mouredev.pro)** y utiliza el cupón **"PYTHON"** con un 10% de descuento en tu primera suscripción.

## ![https://mouredev.com](https://raw.githubusercontent.com/mouredev/mouredev/master/mouredev_emote.png) Hola, mi nombre es Brais Moure.

### Freelance full-stack iOS & Android engineer

[![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UCxPD7bsocoAMq8Dj18kmGyQ?style=social)](https://youtube.com/mouredevapps?sub_confirmation=1)
Expand Down