Skip to content

VolkovEgor/advertising-task

Repository files navigation

Тестовое задание Advertising

Содержание

  1. Описание задачи
  2. Реализация
  3. Архитектура
  4. Endpoints
  5. Запуск
  6. Тестирование
  7. Документация
  8. Нагрузочное тестирование
  9. Примеры

Описание задачи

Необходимо создать сервис для хранения и подачи объявлений. Объявления должны храниться в базе данных. Сервис должен предоставлять API, работающее поверх HTTP в формате JSON.

Метод получения списка объявлений

  • Пагинация: на одной странице должно присутствовать 10 объявлений;
  • Cортировки: по цене (возрастание/убывание) и по дате создания (возрастание/убывание);
  • Поля в ответе: название объявления, ссылка на главное фото (первое в списке), цена.

Метод получения конкретного объявления

  • Обязательные поля в ответе: название объявления, цена, ссылка на главное фото;
  • Опциональные поля (можно запросить, передав параметр fields): описание, ссылки на все фото.

Метод создания объявления:

  • Принимает все вышеперечисленные поля: название, описание, несколько ссылок на фотографии (сами фото загружать никуда не требуется), цена;
  • Возвращает ID созданного объявления и код результата (ошибка или успех).

Реализация

  • Следование дизайну REST API.
  • Подход "Чистой Архитектуры" и техника внедрения зависимости.
  • Работа с фреймворком echo.
  • Работа с БД Postgres с использованием библиотеки sqlx и написанием SQL запросов.
  • Конфигурация приложения - библиотека viper.
  • Реализация Graceful Shutdown.
  • Запуск из Docker.
  • Юнит-тестирование уровней обработчиков, бизнес-логики и взаимодействия с БД классическим способом и с помощью моков - библиотеки testify, mock.
  • Сквозное (E2E) тестирование - BDD фреймворк goconvey.
  • Проверка кода на соответствие стандартам с помощью линтера - утилита golangci-lint
  • Автоматическое создание документации с помощью Swagger 2.0 - библиотека echo-swagger.
  • Непрерывная интеграция - сборка приложения, проверка линтером и запуск тестов в Github action.

Структура проекта:

.
├── pkg
│   ├── error_message  // сообщения об ошибках
│   ├── model          // основные структуры
│   ├── handler        // обработчики запросов
│   ├── service        // бизнес-логика
│   └── repository     // взаимодействие с БД
├── cmd                // точка входа в приложение
├── migrations         // SQL файлы с миграциями
├── scripts            // SQL файлы с тестовыми данными
├── configs            // файлы конфигурации
├── test               // инициализация тестовой БД
└── e2e_test.go        // сквозной тест

Архитектура

Схема

Приложение имеет 3 основных слоя, реализованных в отдельных пакетах.

  • Repository - слой взаимодействия с БД. Методы этого слоя принимают данные от Service и выполняют запросы к БД.
  • Service - слой бизнес-логики. Методы этого слоя принимают данные от Handler и применяют к ним бизнес-правила для достижения цели варианта использования.
  • Handler - слой обработчиков запросов. Содержит методы-обработчики для endpoints.

Пакет Model содержит структуры сущностей, используемых остальными слоями.

Endpoints

  • GET /api/adverts - получение списка объявлений
    • Параметры запроса:
      • page - номер страницы,
      • sort - параметры сортировки в формате [поле сортировки]_[порядок сортировки] (например price_desc).
  • GET /api/adverts/:id - получение объявления по id
    • Параметры запроса: - fields - флаг, если равен True, то вернуть все поля, иначе вернуть название, ссылку на главное фото и цену.
  • POST /api/adverts - создание объявления
    • Тело запроса:
      • title - название объявления,
      • description - описание объявления,
      • photos - ссылки на фотографии,
      • price - цена.

Запуск

make build
make run

Если приложение запускается впервые, необходимо применить миграции к базе данных:

make migrate_up

Для миграций используется golang-migrate/migrate CLI.

Тестирование

Локальный запуск тестов:

make run_test

Для локального запуска тестов необходимо создать тестовую БД. Это можно сделать следующей командой (необходима утилита psql):

make create_test_db

Документация

Для просмотра документации Swagger необходимо запустить приложение и перейти по ссылке http://127.0.0.1:9000/swagger/index.html

Нагрузочное тестирование

Нагрузочное тестирование проведено с помощью утилиты Apache Benchmark. Результаты представлены в файле ab_results.md

Примеры

Запросы сгенерированы из Postman для cURL.

Получение списка объявлений

1. GET для page=1 (без сортировки)

Запрос:

$ curl GET localhost:9000/api/adverts?page=1

Тело ответа:

[
    {
        "id": 1,
        "title": "Advert 1",
        "main_photo": "link1",
        "price": 10000
    },
    {
        "id": 2,
        "title": "Advert 2",
        "main_photo": "link1",
        "price": 60000
    },
    {
        "id": 3,
        "title": "Advert 3",
        "main_photo": "link1",
        "price": 30000
    }
]

2. GET для page=1 и sort=price_asc

Запрос:

$ curl GET localhost:9000/api/adverts?page=1&sort=price_asc

Тело ответа:

[
    {
        "id": 1,
        "title": "Advert 1",
        "main_photo": "link1",
        "price": 10000
    },
    {
        "id": 3,
        "title": "Advert 3",
        "main_photo": "link1",
        "price": 30000
    },
    {
        "id": 2,
        "title": "Advert 2",
        "main_photo": "link1",
        "price": 60000
    }
]

3. GET для page=1 и sort=date_desc

Запрос:

$ curl GET localhost:9000/api/adverts?page=1&sort=date_desc

Тело ответа:

[
    {
        "id": 3,
        "title": "Advert 3",
        "main_photo": "link1",
        "price": 30000
    },
    {
        "id": 2,
        "title": "Advert 2",
        "main_photo": "link1",
        "price": 60000
    },
    {
        "id": 1,
        "title": "Advert 1",
        "main_photo": "link1",
        "price": 10000
    }
]

Получение конкретного объявления

1. GET для id=1

Запрос:

$ curl GET localhost:9000/api/adverts/1

Тело ответа:

{
    "id": 1,
    "title": "Advert 1",
    "photos": [
        "link1"
    ],
    "price": 10000
}

2. GET для id=1 и fields=true

Запрос:

$ curl GET localhost:9000/api/adverts/1?fields=true

Тело ответа:

{
    "id": 1,
    "title": "Advert 1",
    "description": "Description 1",
    "photos": [
        "link1",
        "link2",
        "link3"
    ],
    "price": 10000
}

Создание объявления

Запрос:

$ curl --location --request POST 'localhost:9000/api/adverts' \
--header 'Content-Type: application/json' \
--data-raw '{
    "title": "New advert",
    "description": "Description of new advert",
    "photos": ["link1", "link2"],
    "price": 400000
}'

Тело ответа:

{
    "advert_id": 4
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published