The CloudBlue Connect platform simplifies integration of different business flows between Providers/Distributors and Vendors systems. Namely, it handles the integration of complex business scenarios and provides unified place for communication. That's why APIs are very important part of our day-to-day work. In addition, our teams are focused on providing powerful and simple APIs for our integrators. Providers/Distributors usually use some eCommerce systems to sell services. In this task you are going to write a simple headless eCommerce system that could be integrated with the Cloudblue Connect platform. Since eCommerce systems automate a lot of business scenarios, your task is limited to only one flow: purchasing of new products (usually called the Order Flow). As a result, you should provide a Web Application that allows operating with Orders by making http calls to the application's API.
First of all, it is important to understand what the term Order means in our eCommerce system and what business processes it involves:
- Order is an entity that provides information about what customers want to buy.
- One Order can contain different products with different quantity and different prices. The entity that includes this information in Order is called Order Detail.
- Order can be bound with an entity that represents the same Order in an external system. For example, such a system can be Cloudblue Connect itself. It is required to simplify tracking Orders in different systems.
- Orders are created with the status 'new'.
- Users that process Orders can move them to the following statuses: 'accepted' or 'rejected'.
- Users should not be able to delete 'accepted' Orders.
The Order flow can be described with a simple state diagram below:
After understanding the business area, let's dive into technical implementation details and technical requirements. Your goal is to create a simple Web Application that should provide REST API with support of CRUD operations on Order entity.
- Programming language: Python
- Frameworks: Django + Django REST Framework
- Web application should contain unit tests
- Testing framework: unittest or pytest
- Feel free to use any additional Django library
- Use any SQL database you want
- API should accept and return data only in the JSON format.
- Collections List API should support Paging.
- Collections List API should enable users to define 'limit' and 'offset' query parameters for Paging.
- A response body of Collections List API should return only list of entities.
- Collections List API should return paging information in a header 'Content-Range' via the following format: 'items {from-number}-{to-number}/{total}'.
- There should be proper handling of exceptions in the API.
- There is no need for Authentication and Authorization processes.
- PUT should be implemented as a partial update.
- API should be covered with unit tests.
Database structure can be described with the following schema:
Note: Use DecimalField to store price in OrderDetail
Find detailed API description here
HTTP Method | URL | Filters | Ordering | Response Code |
---|---|---|---|---|
GET | /api/v1/orders | external_id, status | id, status, created_at | 200 |
GET | /api/v1/orders/{id} | - | - | 200 |
POST | /api/v1/orders | - | - | 201 |
PUT | /api/v1/orders/{id} | - | - | 200 |
DELETE | /api/v1/orders/{id} | - | - | 204 |
Note: Users should not be able to delete 'accepted' Orders.
Furthermore, API should support custom nested actions to switch Order between statuses.
HTTP Method | URL | Filters | Ordering | Response Code |
---|---|---|---|---|
POST | /api/v1/orders/{id}/accept | - | - | 200 |
POST | /api/v1/orders/{id}/fail | - | - | 200 |
The following provides detailed description of request/response bodies. In case there is no information for some API, consider request/response bodies as empty.
[{
"id": 1,
"status": "new",
"created_at": "2021-01-01T00:00:00",
"external_id": "PR-123-321-123",
"details": [{
"id": 1,
"product": {"id": 4, "name": "Dropbox"},
"amount": 10,
"price": "12.00"
}, ...]
}, ...]
Note: GET /api/v1/orders/{id} contains same fields in response but returns a particular Order instead of an Order list.
{
"external_id": "PR-123-321-123",
"details": [{
"product": {"id": 4},
"amount": 10,
"price": "12.00"
}, ...]
}
Response body should only contain a created Order entity with order details information.
{
"id": 1,
"status": "new",
"created_at": "2021-01-01T00:00:00",
"external_id": "PR-123-321-123",
"details": [{
"id": 1,
"product": {"id": 4, "name": "Dropbox"},
"amount": 10,
"price": "12.00"
}, ...]
}
Note: Users should only be able to update the 'external_id' field for an Order. Other fields should be ignored even if they were passed in request body.
Note: It should be possible to update Orders only in the status 'new'.
{
"id": 1,
"status": "new",
"created_at": "2021-01-01T00:00:00",
"external_id": "PR-123-321-123-new",
"details": [{
"id": 1,
"product": {"id": 4, "name": "Dropbox"},
"amount": 10,
"price": "12.00"
}, ...]
}
Response body is same as response bodies for GET, POST operations.
{
"id": 1,
"status": "new",
"created_at": "2021-01-01T00:00:00",
"external_id": "PR-123-321-123",
"details": [{
"id": 1,
"product": {"id": 4, "name": "Dropbox"},
"amount": 10,
"price": "12.00"
}, ...]
}
Here is a list of additional requirements for this task. Note that these requirements are not mandatory, but it would be nice to implement them:
- Prepare Docker container for running your solution in the local environment.
- Prepare Docker Compose with application and DB containers to run your solution in the local environment.
- Prepare Docker Compose to run your solution's tests in Docker.