320 lines
7.2 KiB
Markdown
320 lines
7.2 KiB
Markdown
# Family Safety Tracker API
|
|
|
|
REST API для обмена геолокацией между членами семьи.
|
|
|
|
## Аутентификация
|
|
|
|
Сервис использует JWT токены для авторизации.
|
|
|
|
### JWT Токен
|
|
|
|
При успешном `POST /login` возвращается JWT токен:
|
|
|
|
```json
|
|
{
|
|
"user": {...},
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
}
|
|
```
|
|
|
|
**Структура токена:**
|
|
- `issuer: "family_safety_tracker"`
|
|
- `payload: {"user_id": N, "login": "user"}`
|
|
|
|
### Авторизация
|
|
|
|
Защищённые эндпоинты (`/watch`, `/geo`, `/share`) требуют JWT в заголовке:
|
|
|
|
```http
|
|
Authorization: Bearer <jwt_token>
|
|
```
|
|
|
|
---
|
|
|
|
## Таблица эндпоинтов
|
|
|
|
| Метод | URL | Описание | Защита |
|
|
|-------|-----|----------|--------|
|
|
| `POST` | `/login` | Вход в систему | — |
|
|
| `POST` | `/reg` | Регистрация нового пользователя | — |
|
|
| `GET` | `/watch?unique_id=...` | Получить последнюю позицию по share-ссылке | ✅ |
|
|
| `PUT` | `/geo?id=N` | Обновить геопозицию | ✅ |
|
|
| `POST` | `/share` | Создать share-ссылку | ✅ |
|
|
|
|
---
|
|
|
|
## Эндпоинты
|
|
|
|
### `POST /login` — Вход
|
|
|
|
#### Запрос
|
|
|
|
```bash
|
|
curl -X POST http://localhost:9090/reg \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"login": "ivan", "password": "secret123"}'
|
|
```
|
|
|
|
#### PowerShell
|
|
|
|
```powershell
|
|
$body = @{ login = "ivan"; password = "secret123" } | ConvertTo-Json
|
|
Invoke-RestMethod -Uri http://localhost:9090/reg -Method Post -Body $body -ContentType "application/json"
|
|
```
|
|
|
|
#### Успешный ответ (200)
|
|
|
|
```json
|
|
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
```
|
|
|
|
#### Ошибки
|
|
|
|
| Код | Сообщение |
|
|
|-----|-----------|
|
|
| `401` | `Invalid credentials` — неверный логин или пароль |
|
|
|
|
---
|
|
|
|
### `POST /reg` — Регистрация
|
|
|
|
#### Запрос
|
|
|
|
```http
|
|
Content-Type: application/json
|
|
|
|
{"login": "maria", "password": "newpass"}
|
|
```
|
|
|
|
#### Успешный ответ (201)
|
|
|
|
Ничего не возвращается.
|
|
|
|
---
|
|
|
|
### `GET /watch?unique_id=...` — Получить позицию
|
|
|
|
#### Запрос
|
|
|
|
```http
|
|
Authorization: Bearer <jwt_token>
|
|
|
|
GET /watch?unique_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890
|
|
```
|
|
|
|
#### Успешный ответ (200)
|
|
|
|
```json
|
|
{
|
|
"id": 42,
|
|
"x": 55.7558,
|
|
"y": 37.6173,
|
|
"created_at": "2024-01-01T12:00:00Z",
|
|
"expires_at": "2024-01-01T12:05:00Z"
|
|
}
|
|
```
|
|
|
|
#### Ошибки
|
|
|
|
| Код | Сообщение |
|
|
|-----|-----------|
|
|
| `404` | `Share link not found` — неверный `unique_id` |
|
|
| `404` | `No position available` — share-ссылка создана, но позиция не была добавлена |
|
|
|
|
---
|
|
|
|
### `PUT /geo?id=N` — Обновить позицию
|
|
|
|
#### Запрос
|
|
|
|
```http
|
|
Authorization: Bearer <jwt_token>
|
|
Content-Type: application/json
|
|
|
|
PUT /geo?id=1
|
|
|
|
{
|
|
"x": 55.7558,
|
|
"y": 37.6173
|
|
}
|
|
```
|
|
|
|
#### Успешный ответ (200)
|
|
|
|
Ничего не возвращается.
|
|
|
|
---
|
|
|
|
### `POST /share` — Создать share-ссылку
|
|
|
|
#### Запрос
|
|
|
|
```http
|
|
Authorization: Bearer <jwt_token>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"x": 55.7558,
|
|
"y": 37.6173
|
|
}
|
|
```
|
|
|
|
#### Успешный ответ (201)
|
|
|
|
```json
|
|
{
|
|
"geo_id": 5,
|
|
"share_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Примеры запросов
|
|
|
|
### Регистрация
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8080/reg \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"login": "ivan", "password": "secret123"}'
|
|
```
|
|
|
|
### Вход
|
|
|
|
```bash
|
|
curl -X POST http://localhost:9090/login \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"login": "ivan", "password": "secret123"}'
|
|
```
|
|
|
|
#### PowerShell
|
|
|
|
```powershell
|
|
$body = @{ login = "ivan"; password = "secret123" } | ConvertTo-Json
|
|
Invoke-RestMethod -Uri http://localhost:9090/login -Method Post -Body $body -ContentType "application/json"
|
|
```
|
|
|
|
### Создание share-ссылки
|
|
|
|
```bash
|
|
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
|
|
curl -X POST http://localhost:9090/share \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"x": 55.7558, "y": 37.6173}'
|
|
```
|
|
|
|
#### PowerShell
|
|
|
|
```powershell
|
|
$token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
$body = @{ x = 55.7558; y = 37.6173 } | ConvertTo-Json
|
|
Invoke-RestMethod -Uri http://localhost:9090/share -Method Post -Headers @{ Authorization = "Bearer $token"; "Content-Type" = "application/json" } -Body $body
|
|
```
|
|
|
|
### Получение позиции
|
|
|
|
```bash
|
|
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
SHARE_ID="a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
|
|
curl "http://localhost:9090/watch?unique_id=$SHARE_ID" \
|
|
-H "Authorization: Bearer $TOKEN"
|
|
```
|
|
|
|
#### PowerShell
|
|
|
|
```powershell
|
|
$token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
$shareId = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
Invoke-RestMethod -Uri "http://localhost:9090/watch?unique_id=$shareId" -Method Get -Headers @{ Authorization = "Bearer $token" }
|
|
```
|
|
|
|
### Обновление позиции
|
|
|
|
```bash
|
|
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
|
|
curl -X PUT "http://localhost:9090/geo?id=1" \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"x": 55.7558, "y": 37.6173}'
|
|
```
|
|
|
|
#### PowerShell
|
|
|
|
```powershell
|
|
$token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
$body = @{ x = 55.7558; y = 37.6173 } | ConvertTo-Json
|
|
Invoke-RestMethod -Uri "http://localhost:9090/geo?id=1" -Method Put -Headers @{ Authorization = "Bearer $token"; "Content-Type" = "application/json" } -Body $body
|
|
```
|
|
|
|
---
|
|
|
|
## Технические детали
|
|
|
|
### Сервер
|
|
- Порт: `9090` (изменяется через `PORT`)
|
|
|
|
### Технологии
|
|
- **Dart** (SDK `^3.10.1`)
|
|
- **Shelf** + **Shelf Router** — HTTP фреймворк
|
|
- **PostgreSQL** — база данных
|
|
- **bcrypt** — хэширование паролей
|
|
- **dart_jsonwebtoken** — JWT-токены
|
|
- **dotenv** — переменные окружения
|
|
|
|
### Переменные окружения
|
|
|
|
| Переменная | Описание |
|
|
|------------|----------|
|
|
| `PORT` | Порт сервера (по умолчанию 8080) |
|
|
| `POSTGRES_HOST` | Хост PostgreSQL |
|
|
| `POSTGRES_DB` | База данных |
|
|
| `POSTGRES_USER` | Пользователь |
|
|
| `POSTGRES_PASSWORD` | Пароль |
|
|
| `JWT_SECRET` | Секрет для JWT-токенов |
|
|
|
|
### Автоматическая миграция
|
|
|
|
При запуске сервера таблицы создаются автоматически:
|
|
- `users` — пользователи
|
|
- `geopositions` — геопозиции
|
|
- `logs` — логи
|
|
|
|
---
|
|
|
|
## Структура проекта
|
|
|
|
```
|
|
bin/
|
|
├── server.dart # Точка входа
|
|
├── routes/
|
|
│ ├── auth_routes.dart # Маршруты авторизации
|
|
│ └── geo_routes.dart # Маршруты геолокации
|
|
├── repositories/
|
|
│ ├── user_repo.dart
|
|
│ └── geoposition_repo.dart
|
|
├── models/
|
|
│ ├── user.dart
|
|
│ ├── geoposition.dart
|
|
│ └── log.dart
|
|
└── database/
|
|
└── database_provider.dart
|
|
```
|
|
|
|
---
|
|
|
|
## Запуск
|
|
|
|
```bash
|
|
dart pub get
|
|
dart run bin/server.dart
|
|
```
|
|
|
|
## Лицензия
|
|
|
|
MIT
|