Files
quoter/docs/upload-api-detailed.md

299 lines
10 KiB
Markdown
Raw Normal View History

2025-09-01 20:36:15 +03:00
# 📤 API загрузки файлов с квотами - Точная документация
## Обзор
Quoter предоставляет API для загрузки файлов с системой квот и автоматической обработкой различных типов медиа.
## Базовый URL
```
http://localhost:8080
```
## Аутентификация
Все эндпоинты загрузки требуют JWT токен в заголовке:
```
Authorization: Bearer <jwt-token>
```
---
## 📤 Загрузка файлов (УЛУЧШЕННАЯ ВЕРСИЯ)
### POST /
Загружает файл(ы) в S3-совместимое хранилище (Storj) с улучшенной проверкой квот и валидацией.
#### Заголовки запроса
```http
Authorization: Bearer <jwt-token>
Content-Type: multipart/form-data
```
#### Параметры
- **file** (required) - файл(ы) для загрузки в multipart/form-data
#### Поддерживаемые форматы
Автоматическое определение MIME-типа из содержимого файла:
- **Изображения**: JPEG, PNG, GIF, WebP, HEIC
- **Видео**: MP4, WebM, AVI
- **Аудио**: MP3, WAV, OGG
- **Документы**: PDF
#### 🔄 Улучшенная логика обработки
1. **Проверка авторизации** - извлечение и валидация JWT токена
2. **Получение текущей квоты** пользователя из Redis
3. **Предварительная проверка квоты** - пользователь не достиг лимита
4. **Streaming чтение файла** с проверками на каждом chunk:
- Проверка лимита одного файла (500 МБ)
- Проверка общей квоты пользователя
5. **Пропуск пустых файлов**
6. **Определение MIME-типа** из содержимого (не из расширения!)
7. **Генерация UUID имени** файла с правильным расширением
8. **Загрузка в Storj S3**
9. **Обновление квоты** пользователя
10. **Сохранение метаданных** в Redis (с обработкой ошибок)
#### Ограничения
- **Максимальная квота на пользователя**: 5 ГБ (5,368,709,120 байт)
- **Максимальный размер одного файла**: 500 МБ (524,288,000 байт)
- **Проверка квоты происходит во время чтения** (streaming)
- **Поддержка множественных файлов** в одном запросе
#### Успешные ответы
**Один файл:**
```http
HTTP/1.1 200 OK
Content-Type: text/plain
uuid-filename.ext
```
**Несколько файлов:**
```http
HTTP/1.1 200 OK
Content-Type: application/json
{
"uploaded_files": ["uuid1.jpg", "uuid2.png"],
"count": 2
}
```
#### Коды ошибок (ИСПРАВЛЕННЫЕ)
| Код | Условие | Описание |
|-----|---------|----------|
| **400 Bad Request** | Нет файлов | `"No files provided or all files were empty"` |
| **401 Unauthorized** | Отсутствует токен | `"Authorization token required"` |
| **401 Unauthorized** | Неверный токен | `"Invalid authorization token"` |
| **413 Payload Too Large** | 🎯 Превышена квота | `"Author quota limit exceeded"` |
| **413 Payload Too Large** | 🎯 Большой файл | `"Single file size limit exceeded"` |
| **413 Payload Too Large** | 🎯 Превышение при загрузке | `"Author quota limit would be exceeded"` |
| **415 Unsupported Media Type** | Неподдерживаемый MIME | `"Unsupported file format"` |
| **415 Unsupported Media Type** | Нет расширения для MIME | `"Unsupported content type"` |
| **500 Internal Server Error** | Ошибка S3 | `"File upload failed"` |
| **500 Internal Server Error** | Ошибка квоты | `"Failed to update user quota"` |
#### ✅ Исправленные проблемы
1. **Правильный код ошибки для квоты**: 413 Payload Too Large
2. **Efficient memory usage**: streaming с проверками на каждом chunk
3. **Предварительная проверка квоты** перед началом загрузки
4. **Лимит размера одного файла**: 500 МБ
5. **Улучшенная обработка ошибок** с детальными сообщениями
6. **Поддержка множественных файлов** в одном запросе
7. **Детальное логирование** с процентом использования квоты
---
#### 🔄 Как это работает
1. **JWT декодирование** - извлекается `user_id` из токена
2. **Redis lookup** - опциональный поиск сессии по ключу `session:{user_id}:{token}`
3. **Quota lookup** - получение квоты по ключу `quota:{user_id}` из Redis
4. **Activity update** - обновление `last_activity` timestamp (если сессия найдена)
5. **Response building** - объединение данных пользователя и квоты
#### Заголовки запроса
```http
Authorization: Bearer <jwt-token>
```
#### Успешный ответ
```http
HTTP/1.1 200 OK
Content-Type: application/json
{
"user_id": "user_12345",
"username": "john_doe",
"token_type": "session",
"created_at": "1642248600",
"last_activity": "1642335000",
"auth_data": "{\"roles\": [\"user\"], \"permissions\": [...]}",
"device_info": "{\"platform\": \"web\", \"browser\": \"Chrome\"}",
"quota": {
"current_quota": 1073741824,
"max_quota": 5368709120,
"usage_percentage": 20.0
}
}
```
#### Поля ответа
| Поле | Тип | Описание |
|------|-----|----------|
| `user_id` | string | Уникальный ID пользователя |
| `username` | string \| null | Имя пользователя |
| `token_type` | string \| null | Тип токена (обычно "session") |
| `created_at` | string \| null | Unix timestamp создания сессии |
| `last_activity` | string \| null | Unix timestamp последней активности |
| `auth_data` | string \| null | JSON-строка с данными авторизации |
| `device_info` | string \| null | JSON-строка с информацией об устройстве |
| `quota.current_quota` | number | Текущее использование квоты в байтах |
| `quota.max_quota` | number | Максимальная квота в байтах |
| `quota.usage_percentage` | number | Процент использования квоты |
#### Коды ошибок
| Код | Условие | Описание |
|-----|---------|----------|
| **401 Unauthorized** | Отсутствует токен | `"Authorization token required"` |
| **401 Unauthorized** | Неверный JWT | `"Invalid or expired session token"` |
| **401 Unauthorized** | Сессия не найдена | `"Session not found or expired"` |
#### Примеры использования
```bash
# Получение информации о текущем пользователе
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc..." \
http://localhost:8080/
```
---
## 📊 Управление квотами
### GET /quota
Получает информацию о квоте пользователя.
#### Параметры запроса
```
GET /quota?user_id=<user_id>
```
#### Ответ
```json
{
"user_id": "user123",
"current_quota": 1073741824,
"max_quota": 5368709120
}
```
### POST /quota/increase
Увеличивает квоту пользователя (admin-only).
#### Тело запроса
```json
{
"user_id": "user123",
"additional_bytes": 1073741824
}
```
#### Валидация
- `additional_bytes` должно быть > 0
- Требуется админский токен
### POST /quota/set
Устанавливает абсолютное значение квоты (admin-only).
#### Тело запроса
```json
{
"user_id": "user123",
"new_quota_bytes": 2147483648
}
```
---
## 🔍 Получение файлов
### GET /{filename}
Возвращает файл по имени с возможными трансформациями.
#### Параметры URL
- `filename` - имя файла или имя_размер.расширение для миниатюр
#### Query параметры
- `s=<shout_id>` - добавляет оверлей с данными shout (только изображения)
#### Примеры
```bash
GET /uuid-file.jpg # Оригинальный файл
GET /uuid-file_300.jpg # Миниатюра 300px
GET /uuid-file_300.jpg/webp # Миниатюра в WebP
GET /uuid-file.jpg?s=123 # С оверлеем shout
```
---
## 🧪 Примеры использования
### Загрузка файла
```bash
curl -X POST http://localhost:8080/ \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc..." \
-F "file=@photo.jpg"
```
**Ответ при успехе:**
```
c4ca4238-a0b9-23f1-8429-81dc9bdb9a1f.jpg
```
**Ответ при превышении квоты:**
```
HTTP/1.1 401 Unauthorized
Quota exceeded
```
### Проверка квоты
```bash
curl "http://localhost:8080/quota?user_id=user123" \
-H "Authorization: Bearer admin-token"
```
### Увеличение квоты (admin)
```bash
curl -X POST http://localhost:8080/quota/increase \
-H "Authorization: Bearer admin-token" \
-H "Content-Type: application/json" \
-d '{"user_id": "user123", "additional_bytes": 1073741824}'
```
---
## 🔧 Рекомендации по улучшению
1. **Исправить код ошибки квоты**: 401 → 413
2. **Добавить предварительную проверку размера** из Content-Length
3. **Streaming загрузка** вместо полного чтения в память
4. **Лимит размера одного файла**
5. **Детальная валидация MIME-типов**
6. **Метрики использования квот**
---
*Документация актуальна для версии кода на момент создания. Для изменений см. CHANGELOG.md.*