This commit is contained in:
146
docs/API.md
146
docs/API.md
@@ -6,6 +6,26 @@ The Women's Safety App provides a comprehensive API for managing user profiles,
|
||||
|
||||
**Base URL:** `http://localhost:8000` (API Gateway)
|
||||
|
||||
## Swagger Documentation
|
||||
|
||||
Интерактивная документация API доступна через Swagger UI по следующим URL:
|
||||
|
||||
- API Gateway: `http://localhost:8000/docs`
|
||||
- User Service: `http://localhost:8001/docs`
|
||||
- Emergency Service: `http://localhost:8002/docs`
|
||||
- Location Service: `http://localhost:8003/docs`
|
||||
- Calendar Service: `http://localhost:8004/docs`
|
||||
- Notification Service: `http://localhost:8005/docs`
|
||||
- Nutrition Service: `http://localhost:8006/docs`
|
||||
|
||||
Документация в формате ReDoc доступна по адресам:
|
||||
|
||||
- API Gateway: `http://localhost:8000/redoc`
|
||||
- User Service: `http://localhost:8001/redoc`
|
||||
- (и т.д. для остальных сервисов)
|
||||
|
||||
> **Примечание**: Swagger-документация для каждого сервиса доступна только при запущенном соответствующем сервисе. Если сервис не запущен, страница документации будет недоступна.
|
||||
|
||||
## Authentication
|
||||
|
||||
All endpoints except registration and login require JWT authentication.
|
||||
@@ -15,6 +35,29 @@ All endpoints except registration and login require JWT authentication.
|
||||
Authorization: Bearer <jwt_token>
|
||||
```
|
||||
|
||||
### Testing with Swagger UI
|
||||
|
||||
Для тестирования API через Swagger UI:
|
||||
|
||||
1. Запустите необходимые сервисы:
|
||||
```bash
|
||||
./start_services.sh
|
||||
```
|
||||
|
||||
2. Откройте Swagger UI в браузере:
|
||||
```
|
||||
http://localhost:8000/docs
|
||||
```
|
||||
|
||||
3. Получите JWT-токен через эндпоинты `/api/v1/auth/login` или `/api/v1/auth/register`
|
||||
|
||||
4. Авторизуйтесь в Swagger UI:
|
||||
- Нажмите на кнопку "Authorize" в правом верхнем углу
|
||||
- Введите полученный JWT-токен в формате: `Bearer <token>`
|
||||
- Нажмите "Authorize"
|
||||
|
||||
5. Теперь вы можете тестировать все защищенные эндпоинты
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### 🔐 Authentication
|
||||
@@ -247,6 +290,109 @@ Authorization: Bearer <token>
|
||||
}
|
||||
```
|
||||
|
||||
### 🍎 Nutrition Services
|
||||
|
||||
#### Search Food Items
|
||||
```http
|
||||
GET /api/v1/nutrition/foods?query=apple
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{
|
||||
"food_id": "123456",
|
||||
"name": "Apple, raw, with skin",
|
||||
"brand": "",
|
||||
"calories": 52,
|
||||
"serving_size": "100g",
|
||||
"nutrients": {
|
||||
"carbohydrates": 13.8,
|
||||
"protein": 0.3,
|
||||
"fat": 0.2,
|
||||
"fiber": 2.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"food_id": "789012",
|
||||
"name": "Apple juice, unsweetened",
|
||||
"brand": "Example Brand",
|
||||
"calories": 46,
|
||||
"serving_size": "100ml",
|
||||
"nutrients": {
|
||||
"carbohydrates": 11.2,
|
||||
"protein": 0.1,
|
||||
"fat": 0.1,
|
||||
"fiber": 0.2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Add Nutrition Entry
|
||||
```http
|
||||
POST /api/v1/nutrition/entries
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"food_id": "123456",
|
||||
"date": "2025-10-16",
|
||||
"meal_type": "lunch",
|
||||
"quantity": 1.0,
|
||||
"serving_size": "100g",
|
||||
"notes": "Red apple"
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Daily Nutrition Summary
|
||||
```http
|
||||
GET /api/v1/nutrition/daily-summary?date=2025-10-16
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"date": "2025-10-16",
|
||||
"total_calories": 1578,
|
||||
"total_carbohydrates": 175.3,
|
||||
"total_proteins": 78.2,
|
||||
"total_fats": 52.8,
|
||||
"total_water": 1200,
|
||||
"entries": [
|
||||
{
|
||||
"id": 123,
|
||||
"food_name": "Apple, raw, with skin",
|
||||
"meal_type": "lunch",
|
||||
"calories": 52,
|
||||
"quantity": 1.0,
|
||||
"serving_size": "100g"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Track Water Intake
|
||||
```http
|
||||
POST /api/v1/nutrition/water
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"date": "2025-10-16",
|
||||
"amount_ml": 250,
|
||||
"time": "12:30:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 📊 System Status
|
||||
|
||||
#### Check Service Health
|
||||
|
||||
@@ -25,16 +25,16 @@ This document describes the microservices architecture of the Women's Safety App
|
||||
│ Request Routing) │
|
||||
└───────────────────────────┘
|
||||
│
|
||||
┌─────────────┬──────────────┼──────────────┬─────────────┐
|
||||
│ │ │ │ │
|
||||
┌─────────┐ ┌─────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ User │ │Emergency│ │ Location │ │ Calendar │ │Notification │
|
||||
│Service │ │Service │ │ Service │ │ Service │ │ Service │
|
||||
│:8001 │ │:8002 │ │ :8003 │ │ :8004 │ │ :8005 │
|
||||
└─────────┘ └─────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
||||
│ │ │ │ │
|
||||
└─────────────┼──────────────┼──────────────┼─────────────┘
|
||||
│ │ │
|
||||
┌─────────────┬──────────────┼──────────────┬─────────────┬─────────────┐
|
||||
│ │ │ │ │ │
|
||||
┌─────────┐ ┌─────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ User │ │Emergency│ │ Location │ │ Calendar │ │Notification │ │ Nutrition │
|
||||
│Service │ │Service │ │ Service │ │ Service │ │ Service │ │ Service │
|
||||
│:8001 │ │:8002 │ │ :8003 │ │ :8004 │ │ :8005 │ │ :8006 │
|
||||
└─────────┘ └─────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
||||
│ │ │ │ │ │
|
||||
└─────────────┼──────────────┼──────────────┼─────────────┼─────────────┘
|
||||
│ │ │ │
|
||||
┌────────────────────────────────────────────────┐
|
||||
│ Message Bus │
|
||||
│ (Kafka/RabbitMQ) │
|
||||
|
||||
228
docs/FATSECRET_API.md
Normal file
228
docs/FATSECRET_API.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# Работа с FatSecret API в проекте
|
||||
|
||||
Этот документ описывает, как используется API FatSecret для получения данных о продуктах питания и их пищевой ценности в нашем проекте.
|
||||
|
||||
## Настройка API
|
||||
|
||||
### Ключи API
|
||||
Для работы с FatSecret API необходимы следующие ключи:
|
||||
- `FATSECRET_CLIENT_ID` - ID клиента
|
||||
- `FATSECRET_CLIENT_SECRET` - секрет клиента
|
||||
- `FATSECRET_CUSTOMER_KEY` - ключ пользователя (используется как альтернатива CLIENT_ID)
|
||||
|
||||
Эти ключи хранятся в `.env` файле проекта и загружаются в конфигурацию через модуль `shared/config.py`.
|
||||
|
||||
### Методы аутентификации
|
||||
|
||||
FatSecret API поддерживает два метода аутентификации:
|
||||
1. **OAuth 2.0** - требует прокси-сервер с белым списком IP для запроса токенов (не работает в нашем тестовом окружении)
|
||||
2. **OAuth 1.0** - работает напрямую и подписывает каждый запрос (рекомендуется использовать)
|
||||
|
||||
## Примеры использования API
|
||||
|
||||
### Поиск продуктов питания
|
||||
```python
|
||||
def search_food(query, max_results=5):
|
||||
"""Поиск продуктов по названию"""
|
||||
# URL для API
|
||||
url = "https://platform.fatsecret.com/rest/server.api"
|
||||
|
||||
# Параметры запроса
|
||||
params = {
|
||||
'method': 'foods.search',
|
||||
'search_expression': query,
|
||||
'max_results': max_results,
|
||||
'format': 'json'
|
||||
}
|
||||
|
||||
# Подписываем запрос с помощью OAuth 1.0
|
||||
oauth_params = generate_oauth_params("GET", url, params)
|
||||
|
||||
# Отправляем запрос
|
||||
response = requests.get(url, params=oauth_params)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
return None
|
||||
```
|
||||
|
||||
### Получение информации о продукте
|
||||
```python
|
||||
def get_food_details(food_id):
|
||||
"""Получение подробной информации о продукте по ID"""
|
||||
# URL для API
|
||||
url = "https://platform.fatsecret.com/rest/server.api"
|
||||
|
||||
# Параметры запроса
|
||||
params = {
|
||||
'method': 'food.get',
|
||||
'food_id': food_id,
|
||||
'format': 'json'
|
||||
}
|
||||
|
||||
# Подписываем запрос с помощью OAuth 1.0
|
||||
oauth_params = generate_oauth_params("GET", url, params)
|
||||
|
||||
# Отправляем запрос
|
||||
response = requests.get(url, params=oauth_params)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
return None
|
||||
```
|
||||
|
||||
## Генерация OAuth 1.0 подписи
|
||||
|
||||
```python
|
||||
def generate_oauth_params(http_method, url, params):
|
||||
"""Создание и подписание OAuth 1.0 параметров"""
|
||||
# Текущее время в секундах
|
||||
timestamp = str(int(time.time()))
|
||||
# Случайная строка для nonce
|
||||
nonce = ''.join([str(random.randint(0, 9)) for _ in range(8)])
|
||||
|
||||
# Базовый набор параметров OAuth
|
||||
oauth_params = {
|
||||
'oauth_consumer_key': FATSECRET_KEY,
|
||||
'oauth_nonce': nonce,
|
||||
'oauth_signature_method': 'HMAC-SHA1',
|
||||
'oauth_timestamp': timestamp,
|
||||
'oauth_version': '1.0'
|
||||
}
|
||||
|
||||
# Объединяем с параметрами запроса
|
||||
all_params = {**params, **oauth_params}
|
||||
|
||||
# Сортируем параметры по ключу
|
||||
sorted_params = sorted(all_params.items())
|
||||
|
||||
# Создаем строку параметров для подписи
|
||||
param_string = "&".join([f"{urllib.parse.quote(str(k), safe='')}={urllib.parse.quote(str(v), safe='')}"
|
||||
for k, v in sorted_params])
|
||||
|
||||
# Создаем строку для подписи
|
||||
signature_base = f"{http_method}&{urllib.parse.quote(url, safe='')}&{urllib.parse.quote(param_string, safe='')}"
|
||||
|
||||
# Создаем ключ для подписи
|
||||
signing_key = f"{urllib.parse.quote(str(FATSECRET_SECRET), safe='')}&"
|
||||
|
||||
# Создаем HMAC-SHA1 подпись
|
||||
signature = base64.b64encode(
|
||||
hmac.new(
|
||||
signing_key.encode(),
|
||||
signature_base.encode(),
|
||||
hashlib.sha1
|
||||
).digest()
|
||||
).decode()
|
||||
|
||||
# Добавляем подпись к параметрам OAuth
|
||||
all_params['oauth_signature'] = signature
|
||||
|
||||
return all_params
|
||||
```
|
||||
|
||||
## Формат ответа API
|
||||
|
||||
### Поиск продуктов
|
||||
Структура ответа от метода `foods.search`:
|
||||
```json
|
||||
{
|
||||
"foods": {
|
||||
"max_results": "5",
|
||||
"total_results": "1000",
|
||||
"page_number": "0",
|
||||
"food": [
|
||||
{
|
||||
"food_id": "35718",
|
||||
"food_name": "Apples",
|
||||
"food_description": "Per 100g - Calories: 52kcal | Fat: 0.17g | Carbs: 13.81g | Protein: 0.26g",
|
||||
"food_url": "https://www.fatsecret.com/calories-nutrition/usda/apples?portionid=34128"
|
||||
},
|
||||
// ...другие продукты
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Информация о продукте
|
||||
Структура ответа от метода `food.get`:
|
||||
```json
|
||||
{
|
||||
"food": {
|
||||
"food_id": "35718",
|
||||
"food_name": "Apples",
|
||||
"food_type": "Generic",
|
||||
"servings": {
|
||||
"serving": [
|
||||
{
|
||||
"serving_id": "34128",
|
||||
"serving_description": "100g",
|
||||
"calories": "52",
|
||||
"carbohydrate": "13.81",
|
||||
"protein": "0.26",
|
||||
"fat": "0.17",
|
||||
// другие пищевые вещества
|
||||
},
|
||||
// другие варианты порций
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Ограничения API
|
||||
|
||||
1. Функциональность поиска на русском языке может быть недоступна в базовой версии API
|
||||
2. Ограничение на количество запросов в месяц (зависит от уровня доступа)
|
||||
3. OAuth 2.0 требует прокси-сервера, настроенного на определенные IP-адреса
|
||||
|
||||
## Тестирование API
|
||||
|
||||
Для тестирования API можно использовать готовый тестовый скрипт, который находится в корне проекта:
|
||||
|
||||
```bash
|
||||
# Активировать виртуальное окружение
|
||||
source venv/bin/activate
|
||||
|
||||
# Запустить тестовый скрипт
|
||||
python test_fatsecret_api_oauth1.py
|
||||
```
|
||||
|
||||
Вы также можете использовать этот скрипт как шаблон для написания собственных тестов. Примеры использования:
|
||||
|
||||
```python
|
||||
# Импортировать функции из тестового скрипта
|
||||
from test_fatsecret_api_oauth1 import search_food, process_search_results
|
||||
|
||||
# Поиск продуктов на английском
|
||||
result = search_food("chicken breast")
|
||||
process_search_results(result)
|
||||
|
||||
# Поиск продуктов на русском
|
||||
result = search_food("яблоко", locale="ru_RU")
|
||||
process_search_results(result)
|
||||
```
|
||||
|
||||
### Примеры команд для тестирования через cURL
|
||||
|
||||
Для тестирования API через cURL можно использовать следующие команды:
|
||||
|
||||
```bash
|
||||
# Поиск продуктов через nutrition service (требуется авторизация)
|
||||
curl -X POST http://localhost:8006/api/v1/nutrition/search \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||||
-d '{"query": "apple", "max_results": 5}'
|
||||
|
||||
# Прямое тестирование FatSecret API (OAuth 1.0)
|
||||
curl -X GET "https://platform.fatsecret.com/rest/server.api?method=foods.search&search_expression=apple&max_results=5&format=json&oauth_consumer_key=YOUR_CONSUMER_KEY&oauth_signature_method=HMAC-SHA1&oauth_timestamp=TIMESTAMP&oauth_nonce=NONCE&oauth_version=1.0&oauth_signature=YOUR_SIGNATURE"
|
||||
```
|
||||
|
||||
> **Примечание:** Для выполнения прямого запроса к FatSecret API через cURL необходимо сгенерировать правильную OAuth 1.0 подпись. Рекомендуется использовать скрипт `test_fatsecret_api_oauth1.py` вместо этого.
|
||||
|
||||
## Рекомендации по использованию
|
||||
|
||||
1. Использовать OAuth 1.0 для аутентификации, так как он работает без дополнительной инфраструктуры
|
||||
2. Кэшировать результаты запросов, чтобы снизить нагрузку на API
|
||||
3. Обрабатывать возможные ошибки API и предоставлять пользователям понятные сообщения
|
||||
4. Использовать английские запросы для поиска, так как база данных в основном на английском языке
|
||||
593
docs/NUTRITION_API.md
Normal file
593
docs/NUTRITION_API.md
Normal file
@@ -0,0 +1,593 @@
|
||||
# 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
|
||||
```
|
||||
188
docs/NUTRITION_SERVICE_API.md
Normal file
188
docs/NUTRITION_SERVICE_API.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# Nutrition Service API Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
Nutrition Service предоставляет API для отслеживания питания, подсчета калорий и получения информации о продуктах питания через интеграцию с FatSecret API. Сервис позволяет пользователям контролировать свой рацион и отслеживать потребление воды.
|
||||
|
||||
**Base URL:** `/api/v1/nutrition`
|
||||
|
||||
## Authentication
|
||||
|
||||
Все эндпоинты требуют JWT аутентификацию.
|
||||
|
||||
**Headers:**
|
||||
```
|
||||
Authorization: Bearer <jwt_token>
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### 🔍 Поиск продуктов
|
||||
|
||||
#### Найти продукты по названию
|
||||
```http
|
||||
GET /api/v1/nutrition/foods?query=яблоко
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `query` (string, required): Поисковый запрос для поиска продуктов
|
||||
- `page` (number, optional): Номер страницы результатов, по умолчанию 1
|
||||
- `page_size` (number, optional): Количество результатов на странице, по умолчанию 20
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{
|
||||
"food_id": "123456",
|
||||
"name": "Яблоко, сырое, с кожурой",
|
||||
"brand": "",
|
||||
"calories": 52,
|
||||
"serving_size": "100г",
|
||||
"nutrients": {
|
||||
"carbohydrates": 13.8,
|
||||
"protein": 0.3,
|
||||
"fat": 0.2,
|
||||
"fiber": 2.4
|
||||
}
|
||||
}
|
||||
],
|
||||
"total": 25,
|
||||
"page": 1,
|
||||
"page_size": 20
|
||||
}
|
||||
```
|
||||
|
||||
### 📝 Записи о питании
|
||||
|
||||
#### Добавить запись о питании
|
||||
```http
|
||||
POST /api/v1/nutrition/entries
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"food_id": "123456",
|
||||
"date": "2025-10-16",
|
||||
"meal_type": "lunch",
|
||||
"quantity": 1.0,
|
||||
"serving_size": "100г",
|
||||
"notes": "Красное яблоко"
|
||||
}
|
||||
```
|
||||
|
||||
**Варианты типов приема пищи (meal_type):**
|
||||
- `breakfast` - завтрак
|
||||
- `lunch` - обед
|
||||
- `dinner` - ужин
|
||||
- `snack` - перекус
|
||||
|
||||
#### Получить записи о питании
|
||||
```http
|
||||
GET /api/v1/nutrition/entries?date=2025-10-16
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `date` (string, optional): Дата в формате YYYY-MM-DD
|
||||
- `start_date` (string, optional): Начальная дата для получения записей за период
|
||||
- `end_date` (string, optional): Конечная дата для получения записей за период
|
||||
- `meal_type` (string, optional): Фильтр по типу приема пищи
|
||||
|
||||
#### Удалить запись о питании
|
||||
```http
|
||||
DELETE /api/v1/nutrition/entries/{entry_id}
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
### 💧 Отслеживание воды
|
||||
|
||||
#### Добавить запись о потреблении воды
|
||||
```http
|
||||
POST /api/v1/nutrition/water
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"date": "2025-10-16",
|
||||
"amount_ml": 250,
|
||||
"time": "12:30:00"
|
||||
}
|
||||
```
|
||||
|
||||
#### Получить записи о потреблении воды
|
||||
```http
|
||||
GET /api/v1/nutrition/water?date=2025-10-16
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
### 📊 Сводки и статистика
|
||||
|
||||
#### Получить дневную сводку по питанию
|
||||
```http
|
||||
GET /api/v1/nutrition/daily-summary?date=2025-10-16
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"date": "2025-10-16",
|
||||
"total_calories": 1578,
|
||||
"total_carbohydrates": 175.3,
|
||||
"total_proteins": 78.2,
|
||||
"total_fats": 52.8,
|
||||
"total_water": 1200,
|
||||
"entries": [
|
||||
{
|
||||
"id": 123,
|
||||
"food_name": "Яблоко, сырое, с кожурой",
|
||||
"meal_type": "lunch",
|
||||
"calories": 52,
|
||||
"quantity": 1.0,
|
||||
"serving_size": "100г"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Получить недельную аналитику
|
||||
```http
|
||||
GET /api/v1/nutrition/weekly-summary?start_date=2025-10-10
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
## Интеграция с FatSecret API
|
||||
|
||||
Сервис использует FatSecret API для получения информации о питательной ценности продуктов. Ключи API хранятся в конфигурации сервера и не требуют дополнительной настройки со стороны клиента.
|
||||
|
||||
## Примеры использования
|
||||
|
||||
### JavaScript
|
||||
```javascript
|
||||
// Пример поиска продуктов
|
||||
async function searchFoods(query) {
|
||||
const response = await fetch(`http://localhost:8000/api/v1/nutrition/foods?query=${query}`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Пример добавления записи о питании
|
||||
async function addNutritionEntry(entryData) {
|
||||
const response = await fetch('http://localhost:8000/api/v1/nutrition/entries', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
body: JSON.stringify(entryData)
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
```
|
||||
@@ -20,8 +20,13 @@ women-safety-backend/
|
||||
│ ├── 📁 calendar_service/
|
||||
│ │ ├── main.py # Calendar Service (8004)
|
||||
│ │ └── models.py # Calendar models
|
||||
│ └── 📁 notification_service/
|
||||
│ └── main.py # Notification Service (8005)
|
||||
│ ├── 📁 notification_service/
|
||||
│ │ └── main.py # Notification Service (8005)
|
||||
│ └── 📁 nutrition_service/
|
||||
│ ├── main.py # Nutrition Service (8006)
|
||||
│ ├── models.py # Nutrition models
|
||||
│ ├── schemas.py # Nutrition schemas
|
||||
│ └── fatsecret_client.py # FatSecret API client
|
||||
│
|
||||
├── 📁 shared/ # Общие компоненты
|
||||
│ ├── config.py # Конфигурация приложения
|
||||
|
||||
Reference in New Issue
Block a user