develop
Сергей Ванюшкин 2024-02-05 23:14:23 +03:00
parent 5c8c3f16ae
commit b3509d698d
5 changed files with 28 additions and 112 deletions

View File

@ -8,9 +8,9 @@ RUN mkdir -p /usr/src/fastfood
WORKDIR /usr/src/fastfood
COPY ./pyproject.toml .
COPY . .
COPY ./poetry.lock .
COPY ./example.env ./.env
RUN touch /usr/src/RUN_IN_DOCKER

124
README.md
View File

@ -5,78 +5,31 @@ Fastapi веб приложение реализующее api для общеп
Данный проект, это результат выполнения практических домашних заданий интенсива от YLAB Development. Проект реализован на фреймворке fastapi, с использованием sqlalchemy. В качестве базы данных используется postgresql.
## Техническое задание
### Спринт 1 - Создание API
Написать проект на FastAPI с использованием PostgreSQL в качестве БД. В проекте следует реализовать REST API по работе с меню ресторана, все CRUD операции. Для проверки задания, к презентаций будет приложена Postman коллекция с тестами. Задание выполнено, если все тесты проходят успешно.
Даны 3 сущности: Меню, Подменю, Блюдо.
### Спринт 3 - Паттерны и принципы разработки
Зависимости:
- У меню есть подменю, которые к ней привязаны.
- У подменю есть блюда.
1.Вынести бизнес логику и запросы в БД в отдельные слои приложения.
Условия:
- Блюдо не может быть привязано напрямую к меню, минуя подменю.
- Блюдо не может находиться в 2-х подменю одновременно.
- Подменю не может находиться в 2-х меню одновременно.
- Если удалить меню, должны удалиться все подменю и блюда этого меню.
- Если удалить подменю, должны удалиться все блюда этого подменю.
- Цены блюд выводить с округлением до 2 знаков после запятой.
- Во время выдачи списка меню, для каждого меню добавлять кол-во подменю и блюд в этом меню.
- Во время выдачи списка подменю, для каждого подменю добавлять кол-во блюд в этом подменю.
- Во время запуска тестового сценария БД должна быть пуста.
2.Добавить кэширование запросов к API с использованием Redis. Не забыть про инвалидацию кэша.
В папке ./postman_scripts находятся фалы тестов Postman, для тестирования функционала проекта.
3.Добавить pre-commit хуки в проект. Файл yaml будет прикреплен к ДЗ.
### Спринт 2 - Docker && pytest
В этом домашнем задании надо написать тесты для ранее разработанных ендпоинтов вашего API после Вебинара №1.
4.Покрыть проект type hints (тайпхинтами)
Обернуть программные компоненты в контейнеры. Контейнеры должны запускаться по одной команде “docker-compose up -d” или той которая описана вами в readme.md.
5.* Описать ручки API в соответствий c OpenAPI
Образы для Docker:
(API) python:3.10-slim
(DB) postgres:15.1-alpine
6.** Реализовать в тестах аналог Django reverse() для FastAPI
1.Написать CRUD тесты для ранее разработанного API с помощью библиотеки pytest
2.Подготовить отдельный контейнер для запуска тестов. Команду для запуска указать в README.md
3.* Реализовать вывод количества подменю и блюд для Меню через один (сложный) ORM запрос.
4.** Реализовать тестовый сценарий «Проверка кол-ва блюд и подменю в меню» из Postman с помощью pytest
Если FastAPI синхронное - тесты синхронные, Если асинхронное - тесты асинхронные
Требования:
●Код должен проходить все линтеры.
●Код должен соответствовать принципам SOLID, DRY, KISS.
●Проект должен запускаться по одной команде (докер).
●Проект должен проходить все Postman тесты (коллекция с Вебинара №1).
●Тесты написанные вами после Вебинара №2, должны быть актуальны, запускать и успешно проходить
*Оборачиваем приложение в докер.
**CRUD create/update/retrieve/delete.
<a href="https://drive.google.com/drive/folders/13t6fsMO0B6Ls0qYl-uVgAHWOyhFTFv4Z?usp=sharing">Дополнительные материалы</a>
## Возможности
### Спринт 1
В проекте реализованы 3 сущности: Menu, SubMenu и Dish. Для каждого них реализованы 4 метода http запросов: GET, POST, PATCH и DELETE c помощью которых можно управлять данными.
Для Menu доступен метод GET возвращающий все его SubMenu. Аналогично для SubMenu реализован метод для возврата всех Dish.
### Спринт 2
- 1й пункт ТЗ
Тесты реализованы в виде 2х классов
`TastBaseCrud` включает 3 подкласса `Menu`, `Submenu`, `Dish` которые реализуют интерфейсы взаимодействия с endpoint'ами реализованных на предыдущем спринте сущностей. Каждый подкласс реализует методы GET(получение всех сущностей), Get(получение конкректной сущности), Post(создание), Patch(обновление), Delete(удаления). Так же в классе реализованы 3 тестовых функции, которые осуществляют тестирование соответствующих endpoint'ов
`TestContinuity` реализует последовательность сценария «Проверка кол-ва блюд и подменю в меню» из Postman
- 2й пункт ТЗ
Реализованы 3 контейнера(db, app, tests). В db написан блок "проверки здоровья", от которого зависят контейнеры app и test, который гарантирует, что зависимые контейнеры не будут запущены о полной готовности db.
- 3й пункт ТЗ
см. функцию `get_menu_item` на 28 строке в файле
<base_dir>/fastfood/crud/menu.py
- 4й пункт ТЗ
см. класс `TestContinuity` в файле
<base_dir>/tests/test_api.py
Дополнительно:
Контейнеры с проектом и с тестами запускаются разными командами.
## Зависимости
Для локальной установки
- postgresql Для работы сервиса необходима установленная СУБД. Должна быть создана база данных и пользователь с правами на нее.
- poetry - Система управления зависимостями в Python.
Остальное добавится автоматически на этапе установки.
Для запуска в контейнере
- docker
- docker-compose
@ -88,14 +41,6 @@ Fastapi веб приложение реализующее api для общеп
Перейдите в каталог
> `$ cd fastfood`
Создадим файл .env из шаблона
>`$ cp ./example.env ./.env`
Если планируется запуск проекта в Docker контейнере, то `.env` можно не изменять. Если запуск будет локальным, то необходимо изменить переменные окружения, для подключения к БД postgres.
### Docker
Для запуска необходимы установленные приложения docker и docker-compose
Запуск/остановка образов:
- Запуск FAstAPI приложения
@ -113,48 +58,9 @@ Fastapi веб приложение реализующее api для общеп
> `$ docker-compose -f compose_test.yml down`
### Linux
Установите и настройте postgresql согласно офф. документации. Создайте пользователя и бд.
Установите систему управления зависимостями
> `$ pip[x] install poetry`
Клонируйте репозиторий
> `$ git clone https://git.pi3c.ru/pi3c/fastfood.git`
Перейдите в каталог
> `$ cd fastfood`
> `$ poetry install --no-root`
Создастся виртуальное окружение и установятся зависимости
## Запуск
Запуск проекта возможен в 2х режимах:
- Запуск в режиме "prod" с ключем --run-server
Подразумевает наличие уже созданных таблиц в базе данных(например с помощью Alembic). Манипуляций со структурой БД не происходит. Данные не удаляются.
- Запуск в режиме "dev" c ключем --run-test-server
В этом случае при каждом запуске проекта все таблицы с данными удаляются из БД и создаются снова согласно описанных моделей.
Для запуска проекта сначала активируем виртуальное окружение
> `$ poetry shell`
и запускаем проект в соответстующем режиме
>`$ python[x] manage.py --ключ`
вместо этого, так же допускается и другой вариант запуска одной командой без предварительной активации окружения
>`$ poetry run python[x] manage.py --ключ`
## TODO
- Написать тесты для кривых данных
- Провести рефакторинг, много дублирующего кода
- Много чего другого :)
## Авторы

View File

@ -55,6 +55,9 @@ services:
redis:
condition: service_healthy
volumes:
- .:/usr/src/fastfood
restart: always
command: /bin/bash -c 'poetry run python /usr/src/fastfood/manage.py --run-test-server'

View File

@ -45,7 +45,7 @@ async def get_test_session() -> AsyncGenerator[AsyncSession, None]:
yield session
@pytest_asyncio.fixture(scope='session')
@pytest_asyncio.fixture(scope='session', autouse=True)
async def client(event_loop) -> AsyncGenerator[AsyncClient, None]:
app: FastAPI = create_app()
app.dependency_overrides[get_async_session] = get_test_session

View File

@ -2,17 +2,24 @@ def reverse_url(loc: str, **kwargs) -> str:
menu_pref = '/'
submenu_pref = menu_pref + str(kwargs.get('menu_id', '')) + '/submenus/'
dish_pref = submenu_pref + str(kwargs.get('submenu_id', '')) + '/dishes/'
match loc:
case 'menus':
return menu_pref
case 'menu':
return menu_pref + str(kwargs.get('menu_id', ''))
case 'submenus':
return submenu_pref
case 'submenu':
return submenu_pref + str(kwargs.get('submenu_id', ''))
case 'dishes':
return dish_pref
case 'dish':
return dish_pref + str(kwargs.get('dish_id', ''))
return menu_pref