Introducción a FastAPI

1

¿Qué es FastAPI? con Sebastián Ramírez @Tiangolo

2

Instalación de FastAPI y creación de tu primera aplicación

3

Documentación automática con Swagger

4

Métodos HTTP en FastAPI

FastAPI Path Operations

5

Método GET en FastAPI

6

Crear parámetros de ruta en FastAPI

7

Parámetros Query en FastAPI

8

Método POST en FastAPI

9

Métodos PUT y DELETE en FastAPI

Validaciones con Pydantic

10

Creación de esquemas con Pydantic

11

Validaciones de tipos de datos con Pydantic

12

Validaciones de parámetros con Pydantic

13

JSONResponse: Tipos de respuestas en FastAPI

14

Códigos de estado HTTP en FastAPI

Autenticación en FastAPI

15

Flujo de autenticación en FastAPI

16

Generando tokens con PyJWT

17

Validando tokens con PyJWT

18

Middlewares de autenticación en FastAPI

Conexión con bases de datos en FastAPI

19

SQLAlchemy: el ORM de FastAPI

20

Instalación y configuración de SQLAlchemy

21

Creación de modelos con SQLAlchemy

22

Registro de datos con SQLAlchemy

23

Consulta de datos con SQLAlchemy

24

Modificación y eliminación de datos con SQLAlchemy

25

SQLModel: el futuro ORM de FastAPI

Modularización

26

Manejo de errores y middlewares en FastAPI

27

Creación de routers en FastAPI

28

Servicios para consultar datos

29

Servicios para registrar y modificar datos

Despliegue de Aplicación en FastAPI

30

Preparando el proyecto para desplegar a producción

31

¿Cómo elegir entre GitHub y GitLab?

32

Crear repositorio en GitLab

33

Crear Droplet en Digital Ocean

34

Instalación de herramientas para el servidor

35

Ejecutando FastAPI con NGINX

Próximos pasos

36

¿Quieres más cursos de FastAPI?

Bonus

37

Cómo crear una API de alto rendimiento en tiempo récord - Sebastián Ramírez

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Curso de FastAPI

Curso de FastAPI

Pablo España

Pablo España

Middlewares de autenticación en FastAPI

18/37
Recursos

Aportes 13

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Siento que entra con muchos conceptos no vistos. Seria bueno que explique un poco mas lo que esta haciendo.
Hola Profe. ¿De donde surge la pestaña "*http.py"*? ¿Como funciona async? ¿de donde surge \_\_**call**\_\_? En esta clase me perdí completamente.
Sería bueno que separasen los contenidos, además de añadir muchos de los temas que se está saltando en FastAPI, y clasificarlo en al menos 2 cursos: Básico e Intermedio. **Hago énfasis en la importancia de la fecha de los comentarios, y de ser posible hasta del curso.** **Por ej:** En este curso hay sintáxis y librerías que fueron cambiadas por cuestiones de rendimiento, pero no hay forma de saberlo porque no hay fechas, a menos que se consulte directamente en la documentación oficial de FastAPI.
Me parece que este curso está dictado como si fuera una receta de cocina. Hasta ahora hay muchos conceptos y librerías que el profesor introduce pero no explica de donde vienen o por qué razón se los aplica en el diseno de la api
Parce no, demasiados conceptos relativamente complejos en solo 6 minutos o era una clase mas larga para explicar almenos mejor el porque de su existencia(el async y el await, el \_\_**call\_\_**, y el depends), o dos cursos de FastAPI. Además no hay buenas practicas para un entorno de desarrollo real ¿Cómo van a poner los datos de un login en una función así (def login)? Mucho todavía por mejorar Platzi
Un poco de contexto aquí es que se necesita validar no solo el token sino su contenido al momento de "navegar" dentro de nuestra página web, por ende es necesario que el correo ingresado al momento de decodificar el token sea el que se espera por ende en este punto hardcodear admin no es una práctica excelente pero se entiende por cuestiones pedagogicas. JWTBearer es una clase hija, por ende ella hereda los metodos de su clase padre, sin embargo para poder accedor a sus metodos se realiza con super() esto nos va a permitir acceder al metodo **call** el cual recibe una request que realmente va a validar inicialmente si el usuario se encuentra autorizado.
Me sale el siguiente error, que se puede hacer?: Exception in ASGI application Traceback (most recent call last): File "C:\Python312\Lib\site-packages\jwt\api\_jws.py", line 281, in \_load signature = base64url\_decode(crypto\_segment) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\jwt\utils.py", line 33, in base64url\_decode return base64.urlsafe\_b64decode(input\_bytes) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\base64.py", line 134, in urlsafe\_b64decode return b64decode(s) ^^^^^^^^^^^^ File "C:\Python312\Lib\base64.py", line 88, in b64decode return binascii.a2b\_base64(s, strict\_mode=validate) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ binascii.Error: Incorrect padding The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:\Python312\Lib\site-packages\uvicorn\protocols\http\h11\_impl.py", line 404, in run\_asgi result = await app( # type: ignore\[func-returns-value] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\uvicorn\middleware\proxy\_headers.py", line 84, in \_\_call\_\_ return await self.app(scope, receive, send) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\fastapi\applications.py", line 1054, in \_\_call\_\_ await super().\_\_call\_\_(scope, receive, send) File "C:\Python312\Lib\site-packages\starlette\applications.py", line 116, in \_\_call\_\_ await self.middleware\_stack(scope, receive, send) File "C:\Python312\Lib\site-packages\starlette\middleware\errors.py", line 186, in \_\_call\_\_ raise exc File "C:\Python312\Lib\site-packages\starlette\middleware\errors.py", line 164, in \_\_call\_\_ await self.app(scope, receive, \_send) File "C:\Python312\Lib\site-packages\starlette\middleware\exceptions.py", line 62, in \_\_call\_\_ await wrap\_app\_handling\_exceptions(self.app, conn)(scope, receive, send) File "C:\Python312\Lib\site-packages\starlette\\\_exception\_handler.py", line 55, in wrapped\_app raise exc File "C:\Python312\Lib\site-packages\starlette\\\_exception\_handler.py", line 44, in wrapped\_app await app(scope, receive, sender) File "C:\Python312\Lib\site-packages\starlette\routing.py", line 746, in \_\_call\_\_ await route.handle(scope, receive, send) File "C:\Python312\Lib\site-packages\starlette\routing.py", line 288, in handle await self.app(scope, receive, send) File "C:\Python312\Lib\site-packages\starlette\routing.py", line 75, in app await wrap\_app\_handling\_exceptions(app, request)(scope, receive, send) File "C:\Python312\Lib\site-packages\starlette\\\_exception\_handler.py", line 55, in wrapped\_app raise exc File "C:\Python312\Lib\site-packages\starlette\\\_exception\_handler.py", line 44, in wrapped\_app await app(scope, receive, sender) File "C:\Python312\Lib\site-packages\starlette\routing.py", line 70, in app response = await func(request) ^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\fastapi\routing.py", line 285, in app raise e File "C:\Python312\Lib\site-packages\fastapi\routing.py", line 275, in app solved\_result = await solve\_dependencies( ^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\fastapi\dependencies\utils.py", line 598, in solve\_dependencies solved = await call(\*\*sub\_values) ^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\Proyectos\Python\curso-fastapi\main.py", line 15, in \_\_call\_\_ data = validate\_token(auth.credentials) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\Proyectos\Python\curso-fastapi\jwt\_manager.py", line 8, in validate\_token data: dict = decode(token, key="key", algorithms=\['HS256']) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\jwt\api\_jwt.py", line 210, in decode decoded = self.decode\_complete( ^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\jwt\api\_jwt.py", line 151, in decode\_complete decoded = api\_jws.decode\_complete( ^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\jwt\api\_jws.py", line 198, in decode\_complete payload, signing\_input, header, signature = self.\_load(jwt) ^^^^^^^^^^^^^^^ File "C:\Python312\Lib\site-packages\jwt\api\_jws.py", line 283, in \_load raise DecodeError("Invalid crypto padding") from err jwt.exceptions.DecodeError: Invalid crypto padding
```js from fastapi import Depends, FastAPI, Body, HTTPException, Path, Query, Request from fastapi.responses import HTMLResponse, JSONResponse from pydantic import BaseModel, Field from typing import Optional, List from jwt_manager import create_token, validate_token from fastapi.security import HTTPBearer app = FastAPI() app.title = "Mi aplicación con FastAPI" app.version = "0.0.1" class JWTBearer(HTTPBearer): async def __call__(self, request: Request): auth = await super().__call__(request) data = validate_token(auth.credentials) if data['email'] != "[email protected]": raise HTTPException(status_code=403, detail="Credenciales son invalidas") # .decode('utf-8') si sale algun problema Agrega .decode('utf-8') class User(BaseModel): email:str password:str class Movie(BaseModel): id:Optional[int] = None title:str = Field(min_length=3, max_length=15) overview: str = Field(min_length=15, max_length=150) year:int = Field(le = 2024) rating:float = Field(ge=1, le=10) category: str = Field(min_length=3, max_length=20) class Config: json_schema_extra = { "example": { "id":1, "title": "Mi película", "overview":"Descripción de la película", "year": 2022, "rating":9.8, "category": "Acción" } } movies = [ { "id": 1, "title": "Avatar", "overview": "En un exuberante planeta llamado Pandora viven los Na'vi, seres que ...", "year": "2009", "rating": 7.8, "category": "Acción" }, { "id": 2, "title": "Avatar", "overview": "En un exuberante planeta llamado Pandora viven los Na'vi, seres que ...", "year": "2009", "rating": 7.8, "category": "Terror" } ] @app.get("/", tags = ["home"]) def masage(): return HTMLResponse("

Hello World!

") @app.post("/login", tags=["auth"]) def login(user: User): if user.email == "[email protected]" and user.password == "admin": token: str = create_token(user.dict()).decode('utf-8') return JSONResponse(status_code = 200, content=token) return JSONResponse(content=["El correo o el usuario no son correctos"],status_code = 404) @app.get('/movies', tags=['movies'], response_model=List[Movie], status_code=200, dependencies=[Depends(JWTBearer())]) def get_movies() -> List[Movie]: return JSONResponse(status_code=200, content=movies) @app.get("/movies/{id}", tags = ["movies"], response_model = Movie) def get_movie(id: int = Path(ge=1, le=2000)) -> Movie: for item in movies: if item["id"] == id: return JSONResponse(content=item) return JSONResponse(content=["El id no existe"],status_code = 404) """@app.get("/movies/", tags = ["movies"]) def get_movies_by_category(category: str): movies_by_category = [] for movie in movies: if(movie["category"]== category): movies_by_category.append(movie) return movies_by_category""" @app.get('/movies/', tags=['movies'], response_model = List[Movie]) def get_movies_by_category(category: str = Query(min_length=5, max_length=15)) -> List[Movie]: data = [ item for item in movies if item['category'] == category ] return JSONResponse(content=data) @app.post("/movies/", tags = ["movies"], response_model = dict, status_code = 201) def create_movie(movie: Movie) -> dict: movies.append(movie.model_dump()) return JSONResponse(content={"message": "Se ha registrado la película"}, status_code = 201) @app.put("/movies/{id}", tags = ["movies"], response_model = dict, status_code = 200) def update_movie(id: int, movie:Movie) -> dict: for item in movies: if item["id"] == id: item["title"] = movie.title item["overview"] = movie.overview item["year"] = movie.year item["rating"] = movie.rating item["category"] = movie.category return JSONResponse(content={"message": "Se ha modificado la película"}, status_code = 200) @app.delete("/movies/{id}", tags = ["movies"], response_model = dict, status_code = 200) def delete_movie(id: int) -> dict: for item in movies: if item["id"] == id: movies.remove(item) return JSONResponse(content={"message": "Se ha eliminado la película"}, status_code = 200) ```from fastapi import Depends, FastAPI, Body, HTTPException, Path, Query, Requestfrom fastapi.responses import HTMLResponse, JSONResponsefrom pydantic import BaseModel, Fieldfrom typing import Optional, Listfrom jwt\_manager import create\_token, validate\_tokenfrom fastapi.security import HTTPBearer app = FastAPI()app.title = "Mi aplicación con FastAPI"app.version = "0.0.1" class JWTBearer(HTTPBearer):    async def \_\_call\_\_(self, request: Request):        auth = await super().\_\_call\_\_(request)        data = validate\_token(auth.credentials)        if data\['email'] != "[email protected]":            raise HTTPException(status\_code=403, detail="Credenciales son invalidas") # .decode('utf-8') si sale algun problema Agrega .decode('utf-8') class User(BaseModel):    email:str    password:str class Movie(BaseModel):    id:Optional\[int] = None    title:str = Field(min\_length=3, max\_length=15)    overview: str = Field(min\_length=15, max\_length=150)    year:int  = Field(le = 2024)    rating:float = Field(ge=1, le=10)    category: str = Field(min\_length=3, max\_length=20)    class Config:        json\_schema\_extra = {            "example":                {                "id":1,                "title": "Mi película",                "overview":"Descripción de la película",                "year": 2022,                "rating":9.8,                "category": "Acción"            }                    }    movies = \[    {        "id": 1,        "title": "Avatar",        "overview": "En un exuberante planeta llamado Pandora viven los Na'vi, seres que ...",        "year": "2009",        "rating": 7.8,        "category": "Acción"    },    {        "id": 2,        "title": "Avatar",        "overview": "En un exuberante planeta llamado Pandora viven los Na'vi, seres que ...",        "year": "2009",        "rating": 7.8,        "category": "Terror"    }] @app.get("/", tags = \["home"])def masage():    return HTMLResponse("\

Hello World!\

") @app.post("/login", tags=\["auth"])def login(user: User):    if user.email == "[email protected]" and user.password == "admin":        token: str = create\_token(user.dict()).decode('utf-8')        return JSONResponse(status\_code = 200, content=token)    return JSONResponse(content=\["El correo o el usuario no son correctos"],status\_code = 404) @app.get('/movies', tags=\['movies'], response\_model=List\[Movie], status\_code=200, dependencies=\[Depends(JWTBearer())])def get\_movies() -> List\[Movie]:    return JSONResponse(status\_code=200, content=movies) @app.get("/movies/{id}", tags = \["movies"], response\_model = Movie)def get\_movie(id: int = Path(ge=1, le=2000)) -> Movie:    for item in movies:        if item\["id"] == id:            return JSONResponse(content=item)            return JSONResponse(content=\["El id no existe"],status\_code = 404) """@app.get("/movies/", tags = \["movies"])def get\_movies\_by\_category(category: str):    movies\_by\_category = \[]    for movie in movies:        if(movie\["category"]== category):            movies\_by\_category.append(movie)    return movies\_by\_category""" @app.get('/movies/', tags=\['movies'], response\_model = List\[Movie])def get\_movies\_by\_category(category: str = Query(min\_length=5, max\_length=15)) -> List\[Movie]:    data = \[ item for item in movies if item\['category'] == category ]    return JSONResponse(content=data) @app.post("/movies/", tags = \["movies"], response\_model = dict, status\_code = 201)def create\_movie(movie: Movie) -> dict:    movies.append(movie.model\_dump())    return JSONResponse(content={"message": "Se ha registrado la película"}, status\_code = 201) @app.put("/movies/{id}", tags = \["movies"], response\_model = dict, status\_code = 200)def update\_movie(id: int, movie:Movie)  -> dict:    for item in movies:        if item\["id"] == id:            item\["title"] = movie.title            item\["overview"] = movie.overview            item\["year"] = movie.year            item\["rating"] = movie.rating            item\["category"] = movie.category            return JSONResponse(content={"message": "Se ha modificado la película"}, status\_code = 200)            @app.delete("/movies/{id}", tags = \["movies"], response\_model = dict, status\_code = 200)def delete\_movie(id: int) -> dict:    for item in movies:        if item\["id"] == id:            movies.remove(item)            return JSONResponse(content={"message": "Se ha eliminado la película"}, status\_code = 200)
Hasta ahora todo excelente, ya habia programado algunos Apis en otros lenguajes y veo que aqui es un poco mas rapido el desarrollo
En esta clase se ven algunos conceptos que no son 100% relacionados con FastApi. En mi caso ya tengo bases de Python y pues si se entinenden, para las personas que no logren entender algunos coceptos, sería bueno que retrocedan a algún curso de python como tal.
* muy buen profesor, me enganchó su clase teacher, sin embargo: Como es que de un video a otro ya aparecen archivos nuevos y nisiquiera lo comentas como para saber que dejamos de seguir el hilo, simplemente empecé a tener errores porque no sabía que tenias mucha informacion cuya explicacion o tan siquiera mencion pasaste por alto; archivos que nunca mencionaste :(api\_key.py,base.py,http.py,oauth2.py,utlis.py) y no los escribi todos o si estoy equivocado me corriges por favor. Entonces si tuve cierto disgusto por esa forma de proceder. Mala esa de tu parte profe y aun asi estaré viendo mas clases contigo porque no tengo ninguna otra queja ademas de esta, sino todo lo contrario, muy sobresaliente respecto a otros cursos. Con mucho respeto Atte: Alexis Romero
Hasta aquí todo marcha sobre rueda, seguimos avanzando.

no me salió ningún candado en ningún lado, pero en get movies me salieron varias casillas, solo puse el token eun una y presioné execute y salió, pero también salió sin poner nada en las 4 casillas. algo debe estar raro y no creo que sea mi código.