Тестовое задание SellerX
Содержание
- Описание задачи
- Реализация
- Архитектура
- Запуск
- Тестирование
- Документация
- Нагрузочное тестирование
- Примеры
Описание задачи
Цель задания – разработать чат-сервер, предоставляющий HTTP API для работы с чатами и сообщениями пользователя.
Основные сущности
Ниже перечислены основные сущности, которыми должен оперировать сервер.
User
Пользователь приложения. Имеет следующие свойства:
- id - уникальный идентификатор пользователя
- username - уникальное имя пользователя
- created_at - время создания пользователя
Chat
Отдельный чат. Имеет следующие свойства:
- id - уникальный идентификатор чата
- name - уникальное имя чата
- users - список пользователей в чате, отношение многие-ко-многим
- created_at - время создания
Message
Сообщение в чате. Имеет следующие свойства:
- id - уникальный идентификатор сообщения
- chat - ссылка на идентификатор чата, в который было отправлено сообщение
- author - ссылка на идентификатор отправителя сообщения, отношение многие-к-одному
- text - текст отправленного сообщения
- created_at - время создания
Основные API методы
Методы обрабатывают HTTP POST запросы c телом, содержащим все необходимые параметры в JSON.
Добавить нового пользователя
Принимает в качестве полей: имя пользователя.
Ответ: id
созданного пользователя или HTTP-код ошибки.
Создать новый чат между пользователями
Принимает в качестве полей: имя чата и массив id пользователей в чате.
Ответ: id
созданного чата или HTTP-код ошибки.
Количество пользователей не ограничено.
Отправить сообщение в чат от лица пользователя
Принимает в качестве полей: id чата, id автора сообщения и текст сообщения.
Ответ: id
созданного сообщения или HTTP-код ошибки.
Получить список чатов конкретного пользователя
Принимает в качестве полей: id пользователя.
Ответ: cписок всех чатов со всеми полями, отсортированный по времени создания последнего сообщения в чате (от позднего к раннему). Или HTTP-код ошибки.
Получить список сообщений в конкретном чате
Принимает в качестве полей: id чата.
Ответ: список всех сообщений чата со всеми полями, отсортированный по времени создания сообщения (от раннего к позднему). Или HTTP-код ошибки.
Реализация
- Следование дизайну 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 // основные структуры
│ ├── delivery // обработчики запросов
│ ├── service // бизнес-логика
│ └── repository // взаимодействие с БД
├── cmd // точка входа в приложение
├── migrations // SQL файлы с миграциями
├── tet_scripts // SQL файлы с тестовыми данными
├── configs // файлы конфигурации
├── test // инициализация тестовой БД
└── e2e_test.go // сквозной тест
Архитектура
Приложение имеет 3 основных слоя, реализованных в отдельных пакетах.
- Repository - слой взаимодействия с БД. Методы этого слоя принимают данные от Service и выполняют запросы к БД.
- Service - слой бизнес-логики. Методы этого слоя принимают данные от Handler и применяют к ним бизнес-правила для достижения цели варианта использования.
- Delivery - слой обработчиков запросов. Содержит методы-обработчики для endpoints.
Пакет Model содержит структуры сущностей, используемых остальными слоями.
Запуск
make build
make run
Миграции накатываются автоматически при запуске приложения.
Тестирование
Локальный запуск тестов:
make run_test
Для локального запуска тестов необходимо создать тестовую БД. Это можно сделать следующей командой (необходима утилита psql):
make create_test_db
Документация
Для просмотра документации Swagger необходимо запустить приложение и перейти по ссылке http://127.0.0.1:9000/swagger/index.html
Нагрузочное тестирование
Нагрузочное тестирование проведено с помощью утилиты Apache Benchmark.
Результаты представлены в файле ab_results.md
Примеры
Создание пользователя
Запрос:
$ curl --header "Content-Type: application/json" \
--request POST \
--data '{"username": "user_1"}' \
http://localhost:9000/users/add
Тело ответа:
{
"id":"74e6f204-4a47-40b9-aad1-8ea40887867f"
}
Создание чата
Запрос:
$ curl --header "Content-Type: application/json" \
--request POST \
--data '{"name": "chat_1", "users": ["2205ead6-79b6-45a0-93cf-9a1fdcb1f3d8", "74e6f204-4a47-40b9-aad1-8ea40887867f"]}' \
http://localhost:9000/chats/add
Тело ответа:
{
"id":"43e59947-0c56-44a3-b110-51a88f26fe75"
}
Создание сообщения
Запрос:
$ curl --header "Content-Type: application/json" \
--request POST \
--data '{"chat": "43e59947-0c56-44a3-b110-51a88f26fe75", "author": "2205ead6-79b6-45a0-93cf-9a1fdcb1f3d8", "text": "hi"}' \
http://localhost:9000/messages/add
Тело ответа:
{
"id":"27f79a71-b8fd-4f04-a140-d71530945c80"
}
Получение всех чатов пользователя
Запрос:
$ curl --header "Content-Type: application/json" \
--request POST \
--data '{"user": "2205ead6-79b6-45a0-93cf-9a1fdcb1f3d8"}' \
http://localhost:9000/chats/get
Тело ответа:
[
{
"id": "43e59947-0c56-44a3-b110-51a88f26fe75",
"name": "chat_1",
"users": [
"2205ead6-79b6-45a0-93cf-9a1fdcb1f3d8",
"74e6f204-4a47-40b9-aad1-8ea40887867f"
],
"created_at": 1624600288,
"last_message_time": 1624600921
},
{
"id": "8e1ae287-8b99-4e25-9598-db5e6fc77a99",
"name": "Chat 1",
"users": [
"2205ead6-79b6-45a0-93cf-9a1fdcb1f3d8",
"08a1fb77-4d05-4b8a-a9f9-f606c3680516"
],
"created_at": 400,
"last_message_time": 700
},
{
"id": "239998e6-b6b2-406f-994b-20a55e165a88",
"name": "Chat 2",
"users": [
"2205ead6-79b6-45a0-93cf-9a1fdcb1f3d8",
"08a1fb77-4d05-4b8a-a9f9-f606c3680516",
"ea4e8ba2-798f-4535-83e2-e7ae4e776136"
],
"created_at": 500,
"last_message_time": 650
}
]
Получение всех сообщений в чате
Запрос:
$ curl --header "Content-Type: application/json" \
--request POST \
--data '{"chat": "43e59947-0c56-44a3-b110-51a88f26fe75"}' \
http://localhost:9000/messages/get
Тело ответа:
[
{
"id": "27f79a71-b8fd-4f04-a140-d71530945c80",
"chat_id": "43e59947-0c56-44a3-b110-51a88f26fe75",
"author_id": "2205ead6-79b6-45a0-93cf-9a1fdcb1f3d8",
"text": "hi",
"created_at": 1624600921
},
{
"id": "08dea60a-4e7d-4fcc-a209-748b423ee548",
"chat_id": "43e59947-0c56-44a3-b110-51a88f26fe75",
"author_id": "74e6f204-4a47-40b9-aad1-8ea40887867f",
"text": "How have you been?",
"created_at": 1624602090
}
]