├── .gitignore ├── config ├── __init__.py └── database.py ├── jwt_manager.py └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | __pycache__ -------------------------------------------------------------------------------- /config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/platzi/curso-fastapi-sql/20fd210358c08575e9f8b1a54d89d716ba065a4d/config/__init__.py -------------------------------------------------------------------------------- /config/database.py: -------------------------------------------------------------------------------- 1 | import os 2 | from sqlalchemy import create_engine 3 | from sqlalchemy.orm.session import sessionmaker 4 | from sqlalchemy.ext.declarative import declarative_base 5 | 6 | sqlite_file_name = "database.sqlite" 7 | base_dir = os.path.dirname(os.path.realpath(__file__)) 8 | 9 | database_url = f"sqlite:///{os.path.join(base_dir, sqlite_file_name)}" 10 | 11 | engine = create_engine(database_url, echo=True) 12 | 13 | Session = sessionmaker(bind=engine) 14 | 15 | Base = declarative_base() -------------------------------------------------------------------------------- /jwt_manager.py: -------------------------------------------------------------------------------- 1 | from jwt import encode, decode 2 | 3 | def create_token(data: dict) -> str: 4 | token: str = encode(payload=data, key="my_secret_key", algorithm="HS256") 5 | return token 6 | 7 | def validate_token(token: str) -> dict: 8 | data: dict = decode(token, key="my_secret_key", algorithms=['HS256']) 9 | return data -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends, FastAPI, Body, HTTPException, Path, Query, Request 2 | from fastapi.responses import HTMLResponse, JSONResponse 3 | from pydantic import BaseModel, Field 4 | from typing import Optional, List 5 | from jwt_manager import create_token, validate_token 6 | from fastapi.security import HTTPBearer 7 | 8 | app = FastAPI() 9 | app.title = "Mi aplicación con FastAPI" 10 | app.version = "0.0.1" 11 | 12 | class JWTBearer(HTTPBearer): 13 | async def __call__(self, request: Request): 14 | auth = await super().__call__(request) 15 | data = validate_token(auth.credentials) 16 | if data['email'] != "admin@gmail.com": 17 | raise HTTPException(status_code=403, detail="Credenciales son invalidas") 18 | 19 | class User(BaseModel): 20 | email:str 21 | password:str 22 | 23 | class Movie(BaseModel): 24 | id: Optional[int] = None 25 | title: str = Field(min_length=5, max_length=15) 26 | overview: str = Field(min_length=15, max_length=50) 27 | year: int = Field(le=2022) 28 | rating:float = Field(ge=1, le=10) 29 | category:str = Field(min_length=5, max_length=15) 30 | 31 | class Config: 32 | schema_extra = { 33 | "example": { 34 | "id": 1, 35 | "title": "Mi película", 36 | "overview": "Descripción de la película", 37 | "year": 2022, 38 | "rating": 9.8, 39 | "category" : "Acción" 40 | } 41 | } 42 | 43 | movies = [ 44 | { 45 | "id": 1, 46 | "title": "Avatar", 47 | "overview": "En un exuberante planeta llamado Pandora viven los Na'vi, seres que ...", 48 | "year": "2009", 49 | "rating": 7.8, 50 | "category": "Acción" 51 | }, 52 | { 53 | "id": 2, 54 | "title": "Avatar", 55 | "overview": "En un exuberante planeta llamado Pandora viven los Na'vi, seres que ...", 56 | "year": "2009", 57 | "rating": 7.8, 58 | "category": "Acción" 59 | } 60 | ] 61 | 62 | @app.get('/', tags=['home']) 63 | def message(): 64 | return HTMLResponse('

Hello world

') 65 | 66 | 67 | @app.post('/login', tags=['auth']) 68 | def login(user: User): 69 | if user.email == "admin@gmail.com" and user.password == "admin": 70 | token: str = create_token(user.dict()) 71 | return JSONResponse(status_code=200, content=token) 72 | 73 | @app.get('/movies', tags=['movies'], response_model=List[Movie], status_code=200, dependencies=[Depends(JWTBearer())]) 74 | def get_movies() -> List[Movie]: 75 | return JSONResponse(status_code=200, content=movies) 76 | 77 | @app.get('/movies/{id}', tags=['movies'], response_model=Movie) 78 | def get_movie(id: int = Path(ge=1, le=2000)) -> Movie: 79 | for item in movies: 80 | if item["id"] == id: 81 | return JSONResponse(content=item) 82 | return JSONResponse(status_code=404, content=[]) 83 | 84 | @app.get('/movies/', tags=['movies'], response_model=List[Movie]) 85 | def get_movies_by_category(category: str = Query(min_length=5, max_length=15)) -> List[Movie]: 86 | data = [ item for item in movies if item['category'] == category ] 87 | return JSONResponse(content=data) 88 | 89 | @app.post('/movies', tags=['movies'], response_model=dict, status_code=201) 90 | def create_movie(movie: Movie) -> dict: 91 | movies.append(movie) 92 | return JSONResponse(status_code=201, content={"message": "Se ha registrado la película"}) 93 | 94 | @app.put('/movies/{id}', tags=['movies'], response_model=dict, status_code=200) 95 | def update_movie(id: int, movie: Movie)-> dict: 96 | for item in movies: 97 | if item["id"] == id: 98 | item['title'] = movie.title 99 | item['overview'] = movie.overview 100 | item['year'] = movie.year 101 | item['rating'] = movie.rating 102 | item['category'] = movie.category 103 | return JSONResponse(status_code=200, content={"message": "Se ha modificado la película"}) 104 | 105 | @app.delete('/movies/{id}', tags=['movies'], response_model=dict, status_code=200) 106 | def delete_movie(id: int)-> dict: 107 | for item in movies: 108 | if item["id"] == id: 109 | movies.remove(item) 110 | return JSONResponse(status_code=200, content={"message": "Se ha eliminado la película"}) --------------------------------------------------------------------------------