Необходимо написать упрощённое REST API.
Каркас приложения, должен быть стандартный MVC, реализованный через Controller, Entity, Repository, Service. API должно содержать несколько методов:
- Сгенерировать стартовый набор данных, генерируется 20 сущностей "товар", у которых есть идентификатор, название и цена.
- Создать заказ. Метод принимает набор идентификаторов существующих товаров. У заказа есть статус, который может быть в 2 состояниях: новый, оплачено. При создании заказа, по умолчанию выставляется статус "новый". При успешном создании заказа, метод должен возвращать этот номер в ответе на запрос.
- Оплатить заказ. Метод принимает на вход сумму и идентификатор заказа. Если сумма совпадает с суммой заказа и статус заказа "новый", то отправляем http запрос на сайт ya.ru, если статус запроса 200, то меняем статус заказа на "оплачено" (таким образом имитируем работу платёжки).
Таблицу пользователей делать не нужно, считаем, что пользователь всегда авторизирован под id=1, login=admin. Количество товаров в рассчёт не берём, считаем, что их у нас бесконечное количество. Задачу нужно реализовать без фреймворков, никаких триггеров, процедур в mysql использовать нельзя, только обычные sql запросы и транзакции. ORM использовать можно. Использовать сторонние отдельные библиотеки можно (например symfony router). Решение необходимо выложить на github или аналогичный сервис с системой контроля версий. Проект должен быть оформлен так, как будто выкладываете его в продакшн (никакого закомментированного кода, переменные называем сразу как надо и т.п.).
Можно сделать каркас на этих компонентах (для примера, можно и другие):
- symfony/http-kernel
- symfony/http-foundation
- symfony/routing
- symfony/dependency-injection
- doctrine/orm
- guzzlehttp/guzzle
Список пожеланий, что можно еще сделать, но это уже выходит за рамки тестового задания ввиду ограниченного времени, которое можно уделить на решение задачи:
- HTTP authentication
- Idempotency key - для безопасного повторного выполнения запросов без случайного выполнения одной и той же операции дважды.
- Request id - хорошей практикой считается, когда в заголовках ответа имеется идентификтор запроса.
- Rate limit
- Feature tests
- Swagger документация
Комментарии:
- Поддерживается только одна валюта
- Максимальная точность цен 6 знаков после запятой
- OrderItem - решил в этой сущности дублировать цену и название товара, так как после оформления заказа цена и название товара может измениться.
- Было желание добавить к заказу еще одно состояние: в обработке. Но решил не нарушать условия задания:
У заказа есть статус, который может быть в 2 состояниях: новый, оплачено
docker-compose up -d
docker exec -it test-product-fpm composer install
docker exec -it test-product-fpm \
php vendor/doctrine/orm/bin/doctrine orm:schema-tool:update --force --dump-sql
docker exec -it test-product-fpm \
php -r "file_exists('.env') || copy('.env.example', '.env');"
docker exec -it test-product-fpm \
php -r "file_exists('.env.testing') || copy('.env.example', '.env.testing');"
Please update .env
and .env.testing
files.
docker exec -it test-product-fpm vendor/bin/phpunit
POST /api/v1/product/random
Params:
- count | optional | int (min:1, max:100, default:20) - count random products
Example request:
curl -X POST \
http://test-product.local/api/v1/product/random \
-H 'Content-Type: application/json' \
-d '{
"count": 5
}'
Example response:
{
"object": "product_ids",
"data": [
1180,
1181,
1182,
1183,
1184
]
}
POST /api/v1/order
Params:
- product_ids | required | array (min_count:1, max_count:100) - list product ids
Example request:
curl -X POST \
http://test-product.local/api/v1/order \
-H 'Content-Type: application/json' \
-d '{
"product_ids": [1,2,3]
}
'
Example response:
{
"object": "order",
"data": {
"id": 168
}
}
POST /api/v1/order/{order_id}/pay
Params:
- order_id | required | int - order id
- amount | required | int - order amount in the smallest currency unit (e.g., 100 to charge 1 ruble)
Example request:
curl -X POST \
http://test-product.local/api/v1/order/25/pay \
-H 'Content-Type: application/json' \
-d '{
"amount": 100
}
'
Example response:
{
"object": "bool",
"data": true
}
The application uses conventional HTTP response codes to indicate the success or failure of an API request. Errors include an error code that briefly explains the error reported.
Example error response:
{
"code": "resource_missing",
"message": "Not found"
}