-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create basic structure for application (#13)
- Loading branch information
Showing
18 changed files
with
1,005 additions
and
40 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
## 📔 api | ||
Модуль, в котором реализуется API, предоставления http-интерфейса клиентским приложениям. Внутри модуля отсутствует какая-либо бизнес-логика, так как она не должна быть завязана на HTTP. | ||
## 📔 core | ||
Cодержит разные конфигурационные файлы. | ||
## 📔 db | ||
Предоставляет объекты баз данных | ||
(Redis, Elasticsearch) и провайдеры для внедрения зависимостей. | ||
Redis будет использоваться для кеширования, чтобы не нагружать лишний раз Elasticsearch. | ||
|
||
## 📔 models | ||
Содержит классы, описывающие бизнес-сущности, например, фильмы, жанры, актёров. | ||
## 📔 services | ||
Главное в сервисе. В этом модуле находится реализация всей бизнес-логики. |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from http import HTTPStatus | ||
|
||
from fastapi import APIRouter, Depends, HTTPException | ||
from pydantic import BaseModel | ||
from services.film import FilmService, get_film_service | ||
|
||
router = APIRouter() | ||
|
||
|
||
class Film(BaseModel): | ||
id: str | ||
title: str | ||
|
||
|
||
@router.get("/{film_id}", response_model=Film) | ||
async def film_details(film_id: str, film_service: FilmService = Depends(get_film_service)) -> Film: | ||
film = await film_service.get_by_id(film_id) | ||
if not film: | ||
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="film not found") | ||
return Film(id=film.id, title=film.title) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import os | ||
|
||
from logging import config as logging_config | ||
from pathlib import Path | ||
|
||
from core.logger import LOGGING | ||
|
||
logging_config.dictConfig(LOGGING) | ||
|
||
PROJECT_NAME = os.getenv("PROJECT_NAME", "movies") | ||
|
||
REDIS_HOST = os.getenv("REDIS_HOST", "127.0.0.1") | ||
REDIS_PORT = int(os.getenv("REDIS_PORT", "6379")) | ||
|
||
ELASTIC_HOST = os.getenv("ELASTIC_HOST", "127.0.0.1") | ||
ELASTIC_PORT = int(os.getenv("ELASTIC_PORT", "9200")) | ||
ELASTIC_SCHEME = "http" | ||
|
||
BASE_DIR = Path(__file__).resolve().parent.parent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" | ||
LOG_DEFAULT_HANDLERS = ["console"] | ||
|
||
|
||
LOGGING = { | ||
"version": 1, | ||
"disable_existing_loggers": False, | ||
"formatters": { | ||
"verbose": { | ||
"format": LOG_FORMAT, | ||
}, | ||
"default": { | ||
"()": "uvicorn.logging.DefaultFormatter", | ||
"fmt": "%(levelprefix)s %(message)s", | ||
"use_colors": None, | ||
}, | ||
"access": { | ||
"()": "uvicorn.logging.AccessFormatter", | ||
"fmt": "%(levelprefix)s %(client_addr)s - '%(request_line)s' %(status_code)s", | ||
}, | ||
}, | ||
"handlers": { | ||
"console": { | ||
"level": "DEBUG", | ||
"class": "logging.StreamHandler", | ||
"formatter": "verbose", | ||
}, | ||
"default": { | ||
"formatter": "default", | ||
"class": "logging.StreamHandler", | ||
"stream": "ext://sys.stdout", | ||
}, | ||
"access": { | ||
"formatter": "access", | ||
"class": "logging.StreamHandler", | ||
"stream": "ext://sys.stdout", | ||
}, | ||
}, | ||
"loggers": { | ||
"": { | ||
"handlers": LOG_DEFAULT_HANDLERS, | ||
"level": "INFO", | ||
}, | ||
"uvicorn.error": { | ||
"level": "INFO", | ||
}, | ||
"uvicorn.access": { | ||
"handlers": ["access"], | ||
"level": "INFO", | ||
"propagate": False, | ||
}, | ||
}, | ||
"root": { | ||
"level": "INFO", | ||
"formatter": "verbose", | ||
"handlers": LOG_DEFAULT_HANDLERS, | ||
}, | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from core import config | ||
from elasticsearch import AsyncElasticsearch | ||
|
||
es = AsyncElasticsearch( | ||
[{"host": config.ELASTIC_HOST, "port": config.ELASTIC_PORT, "scheme": config.ELASTIC_SCHEME}], | ||
) | ||
|
||
|
||
async def get_elastic() -> AsyncElasticsearch: | ||
return es |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from core import config | ||
from redis.asyncio import Redis | ||
|
||
redis = Redis(host=config.REDIS_HOST, port=config.REDIS_PORT) | ||
|
||
|
||
async def get_redis() -> Redis: | ||
return redis |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import os | ||
|
||
import uvicorn | ||
|
||
from api.v1 import films | ||
from core import config | ||
from db import elastic, redis | ||
from fastapi import FastAPI | ||
from fastapi.responses import ORJSONResponse | ||
|
||
app = FastAPI( | ||
title=config.PROJECT_NAME, | ||
root_path="/api", | ||
default_response_class=ORJSONResponse, | ||
) | ||
|
||
|
||
@app.on_event("startup") | ||
async def startup() -> None: | ||
await redis.redis.initialize() | ||
await elastic.es.info() | ||
|
||
|
||
@app.on_event("shutdown") | ||
async def shutdown() -> None: | ||
await redis.redis.close() | ||
await elastic.es.close() | ||
|
||
|
||
app.include_router(films.router, prefix="/v1/films", tags=["films"]) | ||
|
||
if __name__ == "__main__": | ||
uvicorn.run( | ||
"main:app", | ||
host=str(os.getenv("HOST")), | ||
port=8000, | ||
) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from pydantic import BaseModel | ||
|
||
|
||
class Film(BaseModel): | ||
id: str | ||
title: str | ||
description: str | ||
|
||
class Config: | ||
pass |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from functools import lru_cache | ||
|
||
from db.elastic import get_elastic | ||
from db.redis import get_redis | ||
from elasticsearch import AsyncElasticsearch, NotFoundError | ||
from fastapi import Depends | ||
from models.film import Film | ||
from redis.asyncio import Redis | ||
|
||
FILM_CACHE_EXPIRE_IN_SECONDS = 60 * 5 | ||
|
||
|
||
class FilmService: | ||
def __init__(self, redis: Redis, elastic: AsyncElasticsearch): | ||
self.redis = redis | ||
self.elastic = elastic | ||
|
||
async def get_by_id(self, film_id: str) -> Film | None: | ||
film = await self._film_from_cache(film_id) | ||
if not film: | ||
film = await self._get_film_from_elastic(film_id) | ||
if not film: | ||
return None | ||
await self._put_film_to_cache(film) | ||
|
||
return film | ||
|
||
async def _get_film_from_elastic(self, film_id: str) -> Film | None: | ||
try: | ||
doc = await self.elastic.get(index="movies", id=film_id) | ||
except NotFoundError: | ||
return None | ||
return Film(**doc["_source"]) | ||
|
||
async def _film_from_cache(self, film_id: str) -> Film | None: | ||
data = await self.redis.get(film_id) | ||
if not data: | ||
return None | ||
|
||
return Film.parse_raw(data) | ||
|
||
async def _put_film_to_cache(self, film: Film) -> None: | ||
await self.redis.set(film.id, film.json(), FILM_CACHE_EXPIRE_IN_SECONDS) | ||
|
||
|
||
@lru_cache | ||
def get_film_service( | ||
redis: Redis = Depends(get_redis), | ||
elastic: AsyncElasticsearch = Depends(get_elastic), | ||
) -> FilmService: | ||
return FilmService(redis, elastic) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
|
||
import pytest | ||
|
||
from src.example import hello | ||
from example import hello | ||
|
||
|
||
@pytest.mark.parametrize( | ||
|