All checks were successful
continuous-integration/drone/push Build is passing
593 lines
15 KiB
Markdown
593 lines
15 KiB
Markdown
# API Сервиса Питания (Nutrition Service)
|
||
|
||
Сервис питания предоставляет API для работы с данными о питании, включая поиск продуктов питания, добавление продуктов в дневник питания, отслеживание потребления воды и физической активности.
|
||
|
||
## Основные функции
|
||
|
||
- Поиск продуктов питания через FatSecret API
|
||
- Отслеживание потребления пищи и питательных веществ
|
||
- Учет потребления воды
|
||
- Отслеживание физической активности
|
||
- Установка и отслеживание целей по питанию и активности
|
||
|
||
## Базовый URL
|
||
|
||
```
|
||
http://localhost:8006/api/v1/nutrition/
|
||
```
|
||
|
||
## Swagger-документация
|
||
|
||
Интерактивная документация API доступна через Swagger UI по следующим URL:
|
||
|
||
```
|
||
http://localhost:8006/docs
|
||
```
|
||
|
||
или через ReDoc:
|
||
|
||
```
|
||
http://localhost:8006/redoc
|
||
```
|
||
|
||
> **Примечание**: Swagger-документация доступна только при запущенном сервисе питания. Если сервис не запущен, страница документации будет недоступна.
|
||
|
||
### Использование Swagger UI
|
||
|
||
1. Откройте URL `http://localhost:8006/docs` в браузере
|
||
2. Авторизуйтесь с помощью кнопки "Authorize" в верхней части страницы:
|
||
- Введите ваш JWT токен в формате: `Bearer <token>`
|
||
- Нажмите "Authorize"
|
||
3. Теперь вы можете тестировать все эндпоинты API непосредственно через Swagger UI:
|
||
- Выберите нужный эндпоинт
|
||
- Заполните параметры запроса
|
||
- Нажмите "Execute" для отправки запроса
|
||
|
||

|
||
|
||
## Эндпоинты
|
||
|
||
### Поиск продуктов
|
||
|
||
#### Поиск по названию
|
||
|
||
```http
|
||
POST /api/v1/nutrition/search
|
||
```
|
||
|
||
Параметры запроса:
|
||
```json
|
||
{
|
||
"query": "яблоко",
|
||
"page_number": 0,
|
||
"max_results": 10
|
||
}
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
[
|
||
{
|
||
"id": 1,
|
||
"uuid": "123e4567-e89b-12d3-a456-426614174000",
|
||
"fatsecret_id": "35718",
|
||
"name": "Apple",
|
||
"brand": null,
|
||
"description": "A common fruit",
|
||
"food_type": "Generic",
|
||
"serving_size": "100g",
|
||
"serving_weight_grams": 100.0,
|
||
"calories": 52.0,
|
||
"protein_grams": 0.26,
|
||
"fat_grams": 0.17,
|
||
"carbs_grams": 13.81,
|
||
"fiber_grams": 2.4,
|
||
"sugar_grams": 10.39,
|
||
"sodium_mg": 1.0,
|
||
"cholesterol_mg": 0.0,
|
||
"ingredients": null,
|
||
"is_verified": true,
|
||
"created_at": "2025-10-16T23:10:00"
|
||
}
|
||
]
|
||
```
|
||
|
||
#### Получение информации о продукте
|
||
|
||
```http
|
||
GET /api/v1/nutrition/food/{food_id}
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"uuid": "123e4567-e89b-12d3-a456-426614174000",
|
||
"fatsecret_id": "35718",
|
||
"name": "Apple",
|
||
"brand": null,
|
||
"description": "A common fruit",
|
||
"food_type": "Generic",
|
||
"serving_size": "100g",
|
||
"serving_weight_grams": 100.0,
|
||
"calories": 52.0,
|
||
"protein_grams": 0.26,
|
||
"fat_grams": 0.17,
|
||
"carbs_grams": 13.81,
|
||
"fiber_grams": 2.4,
|
||
"sugar_grams": 10.39,
|
||
"sodium_mg": 1.0,
|
||
"cholesterol_mg": 0.0,
|
||
"ingredients": null,
|
||
"is_verified": true,
|
||
"created_at": "2025-10-16T23:10:00"
|
||
}
|
||
```
|
||
|
||
### Дневник питания
|
||
|
||
#### Добавление записи в дневник питания
|
||
|
||
```http
|
||
POST /api/v1/nutrition/diary
|
||
```
|
||
|
||
Параметры запроса:
|
||
```json
|
||
{
|
||
"food_item_id": 1,
|
||
"entry_date": "2025-10-16",
|
||
"meal_type": "breakfast",
|
||
"quantity": 1.5,
|
||
"unit": "piece",
|
||
"notes": "Morning apple"
|
||
}
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"uuid": "123e4567-e89b-12d3-a456-426614174000",
|
||
"user_id": 42,
|
||
"entry_date": "2025-10-16",
|
||
"meal_type": "breakfast",
|
||
"food_item_id": 1,
|
||
"custom_food_name": null,
|
||
"quantity": 1.5,
|
||
"unit": "piece",
|
||
"calories": 78.0,
|
||
"protein_grams": 0.39,
|
||
"fat_grams": 0.255,
|
||
"carbs_grams": 20.715,
|
||
"notes": "Morning apple",
|
||
"created_at": "2025-10-16T23:15:00"
|
||
}
|
||
```
|
||
|
||
#### Получение записей дневника за день
|
||
|
||
```http
|
||
GET /api/v1/nutrition/diary?date=2025-10-16
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
[
|
||
{
|
||
"id": 1,
|
||
"uuid": "123e4567-e89b-12d3-a456-426614174000",
|
||
"user_id": 42,
|
||
"entry_date": "2025-10-16",
|
||
"meal_type": "breakfast",
|
||
"food_item_id": 1,
|
||
"custom_food_name": null,
|
||
"quantity": 1.5,
|
||
"unit": "piece",
|
||
"calories": 78.0,
|
||
"protein_grams": 0.39,
|
||
"fat_grams": 0.255,
|
||
"carbs_grams": 20.715,
|
||
"notes": "Morning apple",
|
||
"created_at": "2025-10-16T23:15:00"
|
||
}
|
||
]
|
||
```
|
||
|
||
#### Получение сводки за день
|
||
|
||
```http
|
||
GET /api/v1/nutrition/summary?date=2025-10-16
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
{
|
||
"date": "2025-10-16",
|
||
"total_calories": 2150.5,
|
||
"total_protein": 85.2,
|
||
"total_fat": 65.4,
|
||
"total_carbs": 275.3,
|
||
"water_consumed_ml": 1500,
|
||
"activity_minutes": 45,
|
||
"calories_burned": 350,
|
||
"entries_by_meal": {
|
||
"breakfast": [
|
||
{
|
||
"id": 1,
|
||
"food_name": "Apple",
|
||
"quantity": 1.5,
|
||
"unit": "piece",
|
||
"calories": 78.0
|
||
}
|
||
],
|
||
"lunch": [...],
|
||
"dinner": [...],
|
||
"snack": [...]
|
||
}
|
||
}
|
||
```
|
||
|
||
### Потребление воды
|
||
|
||
#### Добавление записи о потреблении воды
|
||
|
||
```http
|
||
POST /api/v1/nutrition/water
|
||
```
|
||
|
||
Параметры запроса:
|
||
```json
|
||
{
|
||
"amount_ml": 250,
|
||
"entry_date": "2025-10-16",
|
||
"notes": "Morning glass"
|
||
}
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"uuid": "123e4567-e89b-12d3-a456-426614174000",
|
||
"user_id": 42,
|
||
"entry_date": "2025-10-16",
|
||
"amount_ml": 250,
|
||
"entry_time": "2025-10-16T08:30:00",
|
||
"notes": "Morning glass"
|
||
}
|
||
```
|
||
|
||
#### Получение записей о потреблении воды за день
|
||
|
||
```http
|
||
GET /api/v1/nutrition/water?date=2025-10-16
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
[
|
||
{
|
||
"id": 1,
|
||
"uuid": "123e4567-e89b-12d3-a456-426614174000",
|
||
"user_id": 42,
|
||
"entry_date": "2025-10-16",
|
||
"amount_ml": 250,
|
||
"entry_time": "2025-10-16T08:30:00",
|
||
"notes": "Morning glass"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"uuid": "223e4567-e89b-12d3-a456-426614174001",
|
||
"user_id": 42,
|
||
"entry_date": "2025-10-16",
|
||
"amount_ml": 500,
|
||
"entry_time": "2025-10-16T12:15:00",
|
||
"notes": "Lunch"
|
||
}
|
||
]
|
||
```
|
||
|
||
### Физическая активность
|
||
|
||
#### Добавление записи о физической активности
|
||
|
||
```http
|
||
POST /api/v1/nutrition/activity
|
||
```
|
||
|
||
Параметры запроса:
|
||
```json
|
||
{
|
||
"entry_date": "2025-10-16",
|
||
"activity_type": "running",
|
||
"duration_minutes": 30,
|
||
"distance_km": 5.2,
|
||
"intensity": "medium",
|
||
"notes": "Morning run"
|
||
}
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"uuid": "123e4567-e89b-12d3-a456-426614174000",
|
||
"user_id": 42,
|
||
"entry_date": "2025-10-16",
|
||
"activity_type": "running",
|
||
"duration_minutes": 30,
|
||
"calories_burned": 300.5,
|
||
"distance_km": 5.2,
|
||
"steps": null,
|
||
"intensity": "medium",
|
||
"notes": "Morning run",
|
||
"created_at": "2025-10-16T09:00:00"
|
||
}
|
||
```
|
||
|
||
#### Получение записей об активности за день
|
||
|
||
```http
|
||
GET /api/v1/nutrition/activity?date=2025-10-16
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
[
|
||
{
|
||
"id": 1,
|
||
"uuid": "123e4567-e89b-12d3-a456-426614174000",
|
||
"user_id": 42,
|
||
"entry_date": "2025-10-16",
|
||
"activity_type": "running",
|
||
"duration_minutes": 30,
|
||
"calories_burned": 300.5,
|
||
"distance_km": 5.2,
|
||
"steps": null,
|
||
"intensity": "medium",
|
||
"notes": "Morning run",
|
||
"created_at": "2025-10-16T09:00:00"
|
||
}
|
||
]
|
||
```
|
||
|
||
### Цели по питанию и активности
|
||
|
||
#### Установка целей
|
||
|
||
```http
|
||
POST /api/v1/nutrition/goals
|
||
```
|
||
|
||
Параметры запроса:
|
||
```json
|
||
{
|
||
"daily_calorie_goal": 2000,
|
||
"protein_goal_grams": 100,
|
||
"fat_goal_grams": 65,
|
||
"carbs_goal_grams": 250,
|
||
"water_goal_ml": 2500,
|
||
"activity_goal_minutes": 45,
|
||
"weight_goal_kg": 75.5,
|
||
"goal_type": "lose_weight"
|
||
}
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"user_id": 42,
|
||
"daily_calorie_goal": 2000,
|
||
"protein_goal_grams": 100,
|
||
"fat_goal_grams": 65,
|
||
"carbs_goal_grams": 250,
|
||
"water_goal_ml": 2500,
|
||
"activity_goal_minutes": 45,
|
||
"weight_goal_kg": 75.5,
|
||
"goal_type": "lose_weight",
|
||
"created_at": "2025-10-16T10:00:00",
|
||
"updated_at": "2025-10-16T10:00:00"
|
||
}
|
||
```
|
||
|
||
#### Получение текущих целей
|
||
|
||
```http
|
||
GET /api/v1/nutrition/goals
|
||
```
|
||
|
||
Ответ:
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"user_id": 42,
|
||
"daily_calorie_goal": 2000,
|
||
"protein_goal_grams": 100,
|
||
"fat_goal_grams": 65,
|
||
"carbs_goal_grams": 250,
|
||
"water_goal_ml": 2500,
|
||
"activity_goal_minutes": 45,
|
||
"weight_goal_kg": 75.5,
|
||
"goal_type": "lose_weight",
|
||
"created_at": "2025-10-16T10:00:00",
|
||
"updated_at": "2025-10-16T10:00:00"
|
||
}
|
||
```
|
||
|
||
## Коды ошибок
|
||
|
||
| Код | Описание |
|
||
|-----|----------|
|
||
| 400 | Некорректный запрос |
|
||
| 401 | Не авторизован |
|
||
| 403 | Доступ запрещен |
|
||
| 404 | Ресурс не найден |
|
||
| 500 | Внутренняя ошибка сервера |
|
||
|
||
## Аутентификация
|
||
|
||
Все запросы к API требуют JWT-токен в заголовке Authorization:
|
||
|
||
```
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
Токен можно получить через сервис авторизации (User Service) по эндпоинту `/api/v1/auth/login`.
|
||
|
||
## Интеграции
|
||
|
||
Сервис питания интегрирован с API FatSecret для получения данных о продуктах питания и их пищевой ценности. Работа с API FatSecret осуществляется через OAuth 1.0 аутентификацию с использованием ключей, указанных в конфигурации приложения.
|
||
|
||
## Тестирование API
|
||
|
||
### Тестирование через Swagger UI
|
||
|
||
Самый простой способ протестировать API - использовать встроенный интерфейс Swagger UI:
|
||
|
||
1. Убедитесь, что сервис питания запущен:
|
||
```bash
|
||
# Запуск всех сервисов
|
||
./start_services.sh
|
||
```
|
||
|
||
2. Откройте в браузере URL: `http://localhost:8006/docs`
|
||
|
||
3. Авторизуйтесь:
|
||
- Нажмите на кнопку "Authorize" в правом верхнем углу
|
||
- Введите ваш JWT токен в формате `Bearer <token>`
|
||
- Нажмите "Authorize"
|
||
|
||
4. Теперь вы можете интерактивно тестировать все эндпоинты:
|
||
- Выберите нужный эндпоинт
|
||
- Заполните параметры запроса
|
||
- Нажмите "Execute"
|
||
- Просмотрите результат запроса и код ответа
|
||
|
||
### Настройка и запуск через CLI
|
||
|
||
1. Убедитесь, что все необходимые сервисы запущены:
|
||
```bash
|
||
# Запуск всех сервисов
|
||
./start_services.sh
|
||
```
|
||
|
||
2. Получите токен аутентификации:
|
||
```bash
|
||
# Регистрация нового пользователя
|
||
curl -X POST http://localhost:8001/api/v1/auth/register -H "Content-Type: application/json" -d '{
|
||
"email": "test_user@example.com",
|
||
"username": "test_user",
|
||
"password": "Test123!",
|
||
"first_name": "Test",
|
||
"last_name": "User",
|
||
"phone": "+79991234567"
|
||
}' | jq
|
||
|
||
# Вход и получение токена
|
||
curl -X POST http://localhost:8001/api/v1/auth/login -H "Content-Type: application/json" -d '{
|
||
"username": "test_user",
|
||
"password": "Test123!"
|
||
}' | jq
|
||
```
|
||
|
||
3. Сохраните полученный токен в переменную для дальнейшего использования:
|
||
```bash
|
||
export TOKEN="ваш_полученный_jwt_токен"
|
||
```
|
||
|
||
### Примеры запросов
|
||
|
||
#### Поиск продуктов
|
||
|
||
```bash
|
||
# Поиск продуктов по названию
|
||
curl -X POST http://localhost:8006/api/v1/nutrition/search \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-d '{
|
||
"query": "apple",
|
||
"max_results": 5
|
||
}' | jq
|
||
```
|
||
|
||
#### Работа с дневником питания
|
||
|
||
```bash
|
||
# Добавление записи в дневник питания
|
||
curl -X POST http://localhost:8006/api/v1/nutrition/diary \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-d '{
|
||
"food_item_id": 1,
|
||
"entry_date": "2025-10-16",
|
||
"meal_type": "breakfast",
|
||
"quantity": 1.5,
|
||
"unit": "piece",
|
||
"notes": "Morning apple"
|
||
}' | jq
|
||
|
||
# Получение дневника за день
|
||
curl -X GET http://localhost:8006/api/v1/nutrition/diary?date=2025-10-16 \
|
||
-H "Authorization: Bearer $TOKEN" | jq
|
||
```
|
||
|
||
#### Работа с водой
|
||
|
||
```bash
|
||
# Добавление записи о потреблении воды
|
||
curl -X POST http://localhost:8006/api/v1/nutrition/water \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-d '{
|
||
"amount_ml": 250,
|
||
"entry_date": "2025-10-16",
|
||
"notes": "Morning glass"
|
||
}' | jq
|
||
|
||
# Получение записей о потреблении воды за день
|
||
curl -X GET http://localhost:8006/api/v1/nutrition/water?date=2025-10-16 \
|
||
-H "Authorization: Bearer $TOKEN" | jq
|
||
```
|
||
|
||
#### Работа с активностью
|
||
|
||
```bash
|
||
# Добавление записи о физической активности
|
||
curl -X POST http://localhost:8006/api/v1/nutrition/activity \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-d '{
|
||
"entry_date": "2025-10-16",
|
||
"activity_type": "running",
|
||
"duration_minutes": 30,
|
||
"distance_km": 5.2,
|
||
"intensity": "medium",
|
||
"notes": "Morning run"
|
||
}' | jq
|
||
|
||
# Получение записей об активности за день
|
||
curl -X GET http://localhost:8006/api/v1/nutrition/activity?date=2025-10-16 \
|
||
-H "Authorization: Bearer $TOKEN" | jq
|
||
```
|
||
|
||
### Автоматизированное тестирование
|
||
|
||
В папке `tests` есть скрипты для автоматизированного тестирования API:
|
||
|
||
```bash
|
||
# Запуск всех тестов для nutrition service
|
||
cd tests
|
||
./test_nutrition_service.sh
|
||
|
||
# Запуск тестов через Python
|
||
python test_nutrition_api.py
|
||
```
|
||
|
||
Для непосредственного тестирования FatSecret API можно использовать скрипт в корне проекта:
|
||
|
||
```bash
|
||
# Тестирование FatSecret API
|
||
python test_fatsecret_api_oauth1.py
|
||
``` |