Вам необходимо создать простое REST API для управления задачами (todo-списком) на языке Go. Это учебный проект для отработки основных навыков веб-разработки на Go.
- Изучить создание HTTP API на Go
- Отработать работу с JSON
- Освоить валидацию данных
- Изучить фильтрацию, поиск и пагинацию
- Понять основы конкурентной безопасности
- Написать базовые тесты
- Язык: Go 1.21+
- Хранилище: В памяти приложения (данные теряются при перезапуске)
- Формат данных: JSON
- Порт: Переменная окружения
PORT
(по умолчанию 8080)
# Установка переменной окружения (опционально)
export PORT=3000
# Запуск приложения
go run main.go
{
"id": "0d3f2b71-8aa0-4f6a-9d0a-6c2a40c2b1ad",
"title": "Написать API спецификацию",
"content": "Создать техническое задание для Tasks API",
"status": "in_progress",
"priority": "high",
"tags": ["работа", "документация"],
"dueDate": "2025-09-20T12:00:00Z",
"createdAt": "2025-09-13T06:00:00Z",
"updatedAt": "2025-09-13T06:30:00Z"
}
Поле | Тип | Описание | Ограничения |
---|---|---|---|
id |
string | Уникальный идентификатор | UUID v4, генерируется автоматически |
title |
string | Название задачи | Обязательное, 1-200 символов |
content |
string | Описание задачи | 0-5000 символов |
status |
string | Статус задачи | todo , in_progress , done (по умолчанию todo ) |
priority |
string | Приоритет | low , normal , high (по умолчанию normal ) |
tags |
array | Теги | Максимум 10 тегов, каждый 1-32 символа |
dueDate |
string|null | Дедлайн | RFC3339 формат или null |
createdAt |
string | Время создания | RFC3339, генерируется автоматически |
updatedAt |
string | Время обновления | RFC3339, обновляется автоматически |
POST /tasks
Создает новую задачу в системе.
Тело запроса:
{
"title": "Купить молоко",
"content": "Не забыть купить молоко по дороге домой",
"priority": "high",
"tags": ["дом", "покупки"],
"dueDate": "2025-09-14T18:00:00Z"
}
Успешный ответ (201 Created):
{
"id": "generated-uuid-here",
"title": "Купить молоко",
"content": "Не забыть купить молоко по дороге домой",
"status": "todo",
"priority": "high",
"tags": ["дом", "покупки"],
"dueDate": "2025-09-14T18:00:00Z",
"createdAt": "2025-09-13T10:00:00Z",
"updatedAt": "2025-09-13T10:00:00Z"
}
Заголовки ответа:
Location: /tasks/{id}
Content-Type: application/json
GET /tasks
Возвращает список задач с возможностью фильтрации, поиска и пагинации.
Параметры запроса:
Параметр | Тип | Описание | Пример |
---|---|---|---|
status |
string | Фильтр по статусу | ?status=todo |
tag |
string | Фильтр по тегу (можно несколько) | ?tag=работа&tag=срочно |
q |
string | Поиск по названию и содержанию | ?q=отчет |
sort |
string | Сортировка по приоритету | ?sort=priority,desc |
page |
int | Номер страницы | ?page=2 |
pageSize |
int | Размер страницы (1-100) | ?pageSize=10 |
Пример запроса:
GET /tasks?status=todo&tag=работа&q=отчет&sort=priority,desc&page=1&pageSize=10
Успешный ответ (200 OK):
{
"items": [
{
"id": "uuid-1",
"title": "Написать отчет",
"content": "Квартальный отчет по продажам",
"status": "todo",
"priority": "high",
"tags": ["работа", "отчеты"],
"dueDate": "2025-09-15T17:00:00Z",
"createdAt": "2025-09-13T09:00:00Z",
"updatedAt": "2025-09-13T09:00:00Z"
}
],
"page": 1,
"pageSize": 10,
"total": 25,
"totalPages": 3
}
GET /tasks/{id}
Возвращает конкретную задачу по её идентификатору.
Успешный ответ (200 OK):
{
"id": "uuid-here",
"title": "Написать отчет",
"content": "Квартальный отчет по продажам",
"status": "in_progress",
"priority": "high",
"tags": ["работа"],
"dueDate": "2025-09-15T17:00:00Z",
"createdAt": "2025-09-13T09:00:00Z",
"updatedAt": "2025-09-13T11:30:00Z"
}
Ошибка (404 Not Found):
{
"error": {
"code": "not_found",
"message": "Task not found",
"details": []
},
"requestId": "req-12345"
}
PATCH /tasks/{id}
Частично обновляет существующую задачу.
Тело запроса (любые поля):
{
"status": "in_progress",
"tags": ["работа", "срочно"]
}
Успешный ответ (200 OK):
Полный объект задачи с обновленными полями и новым updatedAt
.
DELETE /tasks/{id}
Удаляет задачу из системы.
Успешный ответ (204 No Content): Пустое тело ответа.
Код | Описание | Когда используется |
---|---|---|
200 | OK | Успешное чтение или обновление |
201 | Created | Успешное создание |
204 | No Content | Успешное удаление |
400 | Bad Request | Неверный JSON или параметры |
404 | Not Found | Ресурс не найден |
422 | Unprocessable Entity | Ошибки валидации |
500 | Internal Server Error | Внутренняя ошибка сервера |
Все ошибки возвращаются в едином JSON формате:
{
"error": {
"code": "validation_error",
"message": "Ошибка валидации данных",
"details": [
{
"field": "title",
"rule": "required",
"message": "Поле title обязательно для заполнения"
},
{
"field": "tags",
"rule": "max_length",
"message": "Максимальное количество тегов - 10"
}
]
},
"requestId": "req-67890"
}
invalid_json
- Неверный формат JSONvalidation_error
- Ошибки валидации полейnot_found
- Ресурс не найденbad_request
- Неверные параметры запросаinternal
- Внутренняя ошибка сервера
title
- обязательное поле, 1-200 символовcontent
- 0-5000 символовstatus
- толькоtodo
,in_progress
,done
priority
- толькоlow
,normal
,high
tags
- массив до 10 элементов, каждый 1-32 символаdueDate
- корректная дата в формате RFC3339
Те же правила, но все поля опциональны (кроме валидации значений).
- Убираются ведущие и замыкающие пробелы
- Удаляются дубликаты
- Пустые строки после обрезки пробелов - ошибка
curl -X POST http://localhost:8080/tasks \
-H "Content-Type: application/json" \
-d '{
"title": "Изучить Go",
"content": "Пройти туториал по основам Go",
"priority": "high",
"tags": ["обучение", "программирование"]
}'
curl "http://localhost:8080/tasks?status=todo&tag=работа&page=1&pageSize=5"
curl -X PATCH http://localhost:8080/tasks/uuid-here \
-H "Content-Type: application/json" \
-d '{"status": "in_progress"}'
curl -X DELETE http://localhost:8080/tasks/uuid-here
project/
├── main.go # Точка входа
├── internal/
│ ├── handler/ # HTTP обработчики
│ │ └── task.go
│ ├── service/ # Бизнес-логика
│ │ └── task.go
│ ├── store/ # Хранилище данных
│ │ └── memory.go
│ └── model/ # Модели данных
│ └── task.go
└── README.md
- Handler - обрабатывает HTTP запросы, парсит JSON, возвращает ответы
- Service - содержит бизнес-логику, валидацию, координирует работу
- Store - работает с хранилищем данных (интерфейс для будущей замены)
- Используйте
sync.RWMutex
для защиты данных - Операции чтения -
RLock()
- Операции записи -
Lock()
- Для списков делайте копию данных под блокировкой, затем обрабатывайте без неё
- Покрытие кода тестами не менее 10%
- Использование
httptest
для тестирования HTTP handlers - Запуск тестов с флагом
-race
для выявления гонок данных
POST /tasks:
- ✅ Успешное создание
- ❌ Неверный JSON (400)
- ❌ Нарушение валидации (422)
GET /tasks:
- ✅ Получение всех задач
- ✅ Фильтрация по статусу
- ✅ Фильтрация по тегам
- ✅ Поиск по содержимому
- ✅ Сортировка по приоритету
- ✅ Пагинация
GET /tasks/{id}:
- ✅ Найдена (200)
- ❌ Не найдена (404)
PATCH /tasks/{id}:
- ✅ Успешное обновление (200)
- ❌ Задача не найдена (404)
- ❌ Ошибка валидации (422)
DELETE /tasks/{id}:
- ✅ Успешное удаление (204)
- ❌ Задача не найдена (404)
func TestCreateTask(t *testing.T) {
tests := []struct {
name string
requestBody string
expectedStatus int
}{
{
name: "valid task",
requestBody: `{"title":"Test task"}`,
expectedStatus: 201,
},
{
name: "missing title",
requestBody: `{"content":"No title"}`,
expectedStatus: 422,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Тест логика здесь
})
}
}
Для каждого HTTP запроса логируйте:
- HTTP метод
- Путь запроса
- Код ответа
- Время выполнения
- Уникальный ID запроса
Пример лога:
2025-09-13T10:30:45Z INFO [req-12345] POST /tasks - 201 - 15ms
Реализуйте корректное завершение работы:
- Обработка сигналов
SIGTERM
иSIGINT
- Завершение обработки текущих запросов
- Закрытие всех ресурсов
- Отсутствие зависших горутин
- README.md с инструкциями по запуску
- Примеры использования API
- Данная спецификация в репозитории
- Использование
go fmt
- Проверка
go vet
- Идиоматичный Go код
- Обработка всех ошибок
- ✅ Все эндпоинты реализованы и работают
- ✅ Корректные HTTP коды ответов
- ✅ Базовая валидация данных
- ✅ Простые тесты присутствуют
- ✅ + Полная фильтрация и поиск
- ✅ + Правильная пагинация
- ✅ + Единый формат ошибок
- ✅ + Конкурентная безопасность
- ✅ + Comprehensive тесты (покрытие >50%)
- ✅ + Graceful shutdown
- ✅ + Качественная архитектура
Удачи в разработке! 🚀