Тестовое задание на вакансию Intern Backend-Developer в Aviasales

Приложение представляет из себя сервис, который на GET запрос по адресу /flights/<id:int> возвращает из исходного .csv-файла информацию о полёте в JSON-формате типа:

{
    "arrival_time": "1115",
    "departure_time": "2010",
    "number": "SU-275"
}

Названия полей взяты из названия столбоцов исходной .csv-таблицы:

Id,Origin,Destination,DepartureDate,DepartureTime,ArrivalDate,ArrivalTime,Number
1,SVO,BKK,20210701,2010,20210702,1115,SU-275

Дерево проекта

.
├── app
│   ├── Dockerfile
│   └── srcs
│       ├── app.py
│       ├── db.py
│       ├── flight_class.py
│       ├── flights.csv
│       ├── main.py
│       ├── requirements.txt
│       └── uwsgi.ini
├── docker-compose.yml
└── .env

Установка и запуск

  1. Склонировать репозиторий
git clone https://github.com/r-egorov/aviasales-intern
  1. Поместить .csv-файл в директорию ./app/srcs

  2. Указать название .csv-файла в файле .env под переменной CSV_FILE.

  3. Поднимаем сеть контейнеров с помощью docker-compose

docker-compose up -d
  1. Функционал можно проверить, отправляя запросы на адрес хоста, на котором поднят сервис.

Технологии, используемые в проекте

В качестве языка программирования я выбрал Python, потому что мне с ним комфортно работать.

Для создания веб-приложения я выбрал фреймворк Flask, потому что:

  • он лёгкий в освоении;
  • в нем отсутвуют тяжёлые сериализаторы, которые для выполнения задания не нужны

Для чтения и парсинга .csv-файла используется стандартная библиотека csv.

Во время чтения файла данные записываются в PostgreSQL базу данных с помощью SQLAlchemy. С данной ORM я работал впервые. Оказалось, очень удобно.

В качестве продакшен-сервера я выбрал uWSGI (мне посоветовал его Flask, который предупреждает, что просто запускать скрипт в продакшене — нехорошо).

Разворачиваю приложение с помощью docker-compose, поднимая два контейнера:

  • PostgreSQL с томом, в котором сохраняется база данных. Данный контейнер не имеет внешних портов.
  • uWSGI+nginx. У данного контейнера открыт внешний порт 80, на который и поступают запросы. С базой данный он общается по внутренней сети docker network.

Проблемы, возникшие при выполнении проекта

Конечно же, главная проблема — разворачивание приложения. Сначала я поделил инфраструктуру на три сервиса: nginx и uWSGI были в разных контейнерах. Они даже общались между собой, но сгенерированный JSON не доходил до источника запроса. В итоге я узнал, что для этих двух сервисов есть популярное готовое решение.

Перед написанием кода основной проблемой был выбор подхода: каким образом читать файл?

  • Если он небольшого размера, то его можно прочитать в оперативную память и хранить в каком-нибудь словаре или массиве классов.
  • Если большого, то тогда надо использовать БД. К тому же, это позволит сохранять данные между запусками приложения.

Так как в условии не указано, нужно ли валидировать данные, я их не валидирую. Но я проверяю строки .csv-файла на вхождение в мою БД по ID-номеру. Таким образом, между запусками сервиса файлы можно поменять, а в базе данных как останутся предыдущие данные, так и появятся новые без создания дубликатов.

PS

Спасибо за интересное задание!