1. Дизайн REST API для сущности группы
Условие задачи:
Необходимо спроектировать REST API для сущности Группа.
Нужно предложить интерфейс для:
- создания группы
- получения группы или списка групп
- изменения группы
- удаления группы
- добавления и удаления связей, если группа содержит сотрудников или вложенные группы
Пример интерфейса:
- Создание группы:
POST /api/v1/groups/
- Получение списка групп:
GET /api/v1/groups/
- Получение одной группы:
GET /api/v1/groups/{group_id}/
- Частичное изменение группы:
PATCH /api/v1/groups/{group_id}/
- Полное обновление группы:
PUT /api/v1/groups/{group_id}/
- Удаление группы:
DELETE /api/v1/groups/{group_id}/
Спойлеры к решению
Подсказки
- Основной ресурс —
groups. - Для создания группы используется
POST /api/v1/groups/. - Для получения списка групп используется
GET /api/v1/groups/. - Для получения одной группы используется
GET /api/v1/groups/{group_id}/. - Для частичного изменения используется
PATCH. - Для полного обновления используется
PUT. - Для удаления используется
DELETE. - Связи с сотрудниками и вложенными группами лучше вынести в отдельные endpoints.
- Добавление связи удобно делать через
POST. - Удаление связи удобно делать через
DELETE.
Решение
Основной REST API для групп #
POST /api/v1/groups/
Создание группы.
Пример запроса:
{
"name": "Backend",
"description": "Backend development team"
}
Пример ответа:
{
"id": 1,
"name": "Backend",
"description": "Backend development team"
}
Получение списка групп:
GET /api/v1/groups/
Пример ответа:
[
{
"id": 1,
"name": "Backend",
"description": "Backend development team"
},
{
"id": 2,
"name": "Python",
"description": "Python developers"
}
]
Получение одной группы:
GET /api/v1/groups/{group_id}/
Пример ответа:
{
"id": 1,
"name": "Backend",
"description": "Backend development team",
"employees": [
{
"id": 10,
"personnel_number": "EMP-001",
"name": "Ivan Ivanov",
"email": "ivan@example.com"
}
],
"child_groups": [
{
"id": 2,
"name": "Python"
}
],
"parent_groups": []
}
Частичное изменение группы:
PATCH /api/v1/groups/{group_id}/
Пример запроса:
{
"description": "Backend and API development team"
}
Полное обновление группы:
PUT /api/v1/groups/{group_id}/
Пример запроса:
{
"name": "Backend",
"description": "Backend and API development team"
}
Удаление группы:
DELETE /api/v1/groups/{group_id}/
Пример ответа:
204 No Content
API для сотрудников внутри группы #
Добавить сотрудника в группу:
POST /api/v1/groups/{group_id}/employees/
Пример запроса:
{
"employee_id": 10
}
Пример ответа:
{
"group_id": 1,
"employee_id": 10
}
Удалить сотрудника из группы:
DELETE /api/v1/groups/{group_id}/employees/{employee_id}/
Пример ответа:
204 No Content
Получить сотрудников группы:
GET /api/v1/groups/{group_id}/employees/
Пример ответа:
[
{
"id": 10,
"personnel_number": "EMP-001",
"name": "Ivan Ivanov",
"email": "ivan@example.com"
}
]
API для вложенных групп #
Добавить вложенную группу:
POST /api/v1/groups/{group_id}/child-groups/
Пример запроса:
{
"child_group_id": 2
}
Это означает, что группа 2 будет добавлена внутрь группы 1.
Пример ответа:
{
"parent_group_id": 1,
"child_group_id": 2
}
Удалить вложенную группу:
DELETE /api/v1/groups/{group_id}/child-groups/{child_group_id}/
Пример ответа:
204 No Content
Получить вложенные группы:
GET /api/v1/groups/{group_id}/child-groups/
Пример ответа:
[
{
"id": 2,
"name": "Python",
"description": "Python developers"
}
]
Получить родительские группы:
GET /api/v1/groups/{group_id}/parent-groups/
Пример ответа:
[
{
"id": 1,
"name": "Backend",
"description": "Backend development team"
}
]
Итоговый список endpoints #
POST /api/v1/groups/
GET /api/v1/groups/
GET /api/v1/groups/{group_id}/
PATCH /api/v1/groups/{group_id}/
PUT /api/v1/groups/{group_id}/
DELETE /api/v1/groups/{group_id}/
GET /api/v1/groups/{group_id}/employees/
POST /api/v1/groups/{group_id}/employees/
DELETE /api/v1/groups/{group_id}/employees/{employee_id}/
GET /api/v1/groups/{group_id}/child-groups/
POST /api/v1/groups/{group_id}/child-groups/
DELETE /api/v1/groups/{group_id}/child-groups/{child_group_id}/
GET /api/v1/groups/{group_id}/parent-groups/
Важные проверки #
1. Нельзя создать две группы с одинаковым name, если name должен быть уникальным.
2. Нельзя добавить в группу несуществующего сотрудника.
3. Нельзя добавить несуществующую вложенную группу.
4. Нельзя добавить группу саму в себя.
5. Желательно запретить циклические связи групп.
6. Повторное добавление одной и той же связи должно либо игнорироваться, либо возвращать 409 Conflict.
Пример ошибки при попытке добавить группу саму в себя:
{
"detail": "Group cannot contain itself"
}
Пример ошибки при повторном добавлении связи:
{
"detail": "Relation already exists"
}
Такой интерфейс разделяет обычные CRUD-операции над группой и операции управления связями. Это делает API понятным: сама группа редактируется через /groups/{group_id}/, а связи с сотрудниками и вложенными группами управляются через отдельные вложенные ресурсы.