This commit is contained in:
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. Использовать английские запросы для поиска, так как база данных в основном на английском языке
|
||||
Reference in New Issue
Block a user