656 lines
16 KiB
Markdown
656 lines
16 KiB
Markdown
# Руководство по API для фронтенда
|
||
|
||
## Обзор изменений
|
||
|
||
После рефакторинга старый `ParserController` был разделен на три специализированных контроллера для лучшей организации и масштабируемости:
|
||
|
||
- **`MarketItemController`** (`/api/items`) - для получения данных
|
||
- **`ParserAdminController`** (`/api/admin/parsers`) - для управления парсерами
|
||
- **`HealthCheckController`** (`/api/health`) - для мониторинга системы
|
||
|
||
---
|
||
|
||
## 📊 MarketItemController - Получение данных
|
||
|
||
**Базовый URL**: `/api/items`
|
||
|
||
### 1. Получение списка новостей с фильтрацией и пагинацией
|
||
|
||
```http
|
||
GET /api/items
|
||
```
|
||
|
||
**Параметры запроса:**
|
||
|
||
- `sourceName` (optional) - фильтр по источнику (например: "Kursiv Media", "Kapital.kz", "LSM.kz", "РБК", "Ведомости")
|
||
- `startDate` (optional) - начальная дата в формате ISO (например: "2024-01-01T00:00:00")
|
||
- `endDate` (optional) - конечная дата в формате ISO (например: "2024-12-31T23:59:59")
|
||
- `page` (optional) - номер страницы (по умолчанию: 0)
|
||
- `size` (optional) - размер страницы (по умолчанию: 20)
|
||
- `sort` (optional) - сортировка (по умолчанию: "publishedAt,desc")
|
||
|
||
**Примеры запросов:**
|
||
|
||
```javascript
|
||
// Получить все новости
|
||
fetch('/api/items');
|
||
|
||
// Получить новости с пагинацией
|
||
fetch('/api/items?page=0&size=10');
|
||
|
||
// Получить новости от конкретного источника
|
||
fetch('/api/items?sourceName=Kursiv Media');
|
||
|
||
// Получить новости за последние 7 дней
|
||
const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
|
||
fetch(`/api/items?startDate=${weekAgo}`);
|
||
|
||
// Получить новости с сортировкой по дате (старые сначала)
|
||
fetch('/api/items?sort=publishedAt,asc');
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Записи получены успешно",
|
||
"data": {
|
||
"content": [
|
||
{
|
||
"id": "64f1a2b3c4d5e6f7g8h9i0j1",
|
||
"sourceName": "Kursiv Media",
|
||
"url": "https://kursiv.media/news/example",
|
||
"title": "Заголовок новости",
|
||
"publishedAt": "2024-01-15T10:30:00",
|
||
"addedAt": "2024-01-15T10:35:00",
|
||
"rawText": "Текст новости без HTML тегов",
|
||
"hash": "abc123def456...",
|
||
"category": "Бизнес",
|
||
"analytics": {
|
||
"summary": null,
|
||
"sentiment": null,
|
||
"tags": [],
|
||
"entities": {}
|
||
}
|
||
}
|
||
],
|
||
"pageable": {
|
||
"sort": {
|
||
"sorted": true,
|
||
"unsorted": false
|
||
},
|
||
"pageNumber": 0,
|
||
"pageSize": 20,
|
||
"offset": 0,
|
||
"paged": true,
|
||
"unpaged": false
|
||
},
|
||
"totalElements": 150,
|
||
"totalPages": 8,
|
||
"last": false,
|
||
"first": true,
|
||
"numberOfElements": 20,
|
||
"size": 20,
|
||
"number": 0,
|
||
"empty": false
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. Получение новости по ID
|
||
|
||
```http
|
||
GET /api/items/{id}
|
||
```
|
||
|
||
**Пример:**
|
||
|
||
```javascript
|
||
fetch('/api/items/64f1a2b3c4d5e6f7g8h9i0j1');
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "Функция поиска по ID пока не реализована"
|
||
}
|
||
```
|
||
|
||
### 3. Получение статистики
|
||
|
||
```http
|
||
GET /api/items/stats
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Статистика получена успешно",
|
||
"data": {
|
||
"totalItems": 1250,
|
||
"sourceStatistics": {
|
||
"Kursiv Media": 300,
|
||
"Kapital.kz": 250,
|
||
"LSM.kz": 200,
|
||
"РБК": 300,
|
||
"Ведомости": 200
|
||
},
|
||
"lastUpdate": "2024-01-15T10:35:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. Получение списка источников
|
||
|
||
```http
|
||
GET /api/items/sources
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Источники получены успешно",
|
||
"data": ["Kursiv Media", "Kapital.kz", "LSM.kz", "РБК", "Ведомости"]
|
||
}
|
||
```
|
||
|
||
### 5. Получение новостей по конкретному источнику
|
||
|
||
```http
|
||
GET /api/items/source/{sourceName}
|
||
```
|
||
|
||
**Пример:**
|
||
|
||
```javascript
|
||
fetch('/api/items/source/Kursiv Media?page=0&size=10');
|
||
```
|
||
|
||
**Ответ:** Аналогичен ответу от `/api/items`, но только с новостями от указанного источника.
|
||
|
||
---
|
||
|
||
## ⚙️ ParserAdminController - Управление парсерами
|
||
|
||
**Базовый URL**: `/api/admin/parsers`
|
||
|
||
> ⚠️ **Важно**: Эти эндпоинты предназначены для административных функций и могут потребовать аутентификации в будущем.
|
||
|
||
### 1. Запуск конкретного парсера
|
||
|
||
```http
|
||
POST /api/admin/parsers/parse/{sourceName}
|
||
```
|
||
|
||
**Доступные источники:**
|
||
|
||
- `kursiv`
|
||
- `kapital`
|
||
- `lsm`
|
||
- `rbc`
|
||
- `vedomosti`
|
||
|
||
**Пример:**
|
||
|
||
```javascript
|
||
// Запустить парсер Kursiv
|
||
fetch('/api/admin/parsers/parse/kursiv', { method: 'POST' });
|
||
|
||
// Запустить парсер РБК
|
||
fetch('/api/admin/parsers/parse/rbc', { method: 'POST' });
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Парсинг kursiv завершен",
|
||
"data": {
|
||
"source": "kursiv",
|
||
"processedItems": 15,
|
||
"totalItemsInDb": 1265,
|
||
"status": "completed"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. Запуск всех парсеров
|
||
|
||
```http
|
||
POST /api/admin/parsers/parse/all
|
||
```
|
||
|
||
**Пример:**
|
||
|
||
```javascript
|
||
fetch('/api/admin/parsers/parse/all', { method: 'POST' });
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Парсинг всех источников завершен",
|
||
"data": [
|
||
{
|
||
"source": "kursiv",
|
||
"processedItems": 12,
|
||
"totalItemsInDb": 1277,
|
||
"status": "completed"
|
||
},
|
||
{
|
||
"source": "kapital",
|
||
"processedItems": 8,
|
||
"totalItemsInDb": 1285,
|
||
"status": "completed"
|
||
},
|
||
{
|
||
"source": "lsm",
|
||
"processedItems": 5,
|
||
"totalItemsInDb": 1290,
|
||
"status": "completed"
|
||
},
|
||
{
|
||
"source": "rbc",
|
||
"processedItems": 20,
|
||
"totalItemsInDb": 1310,
|
||
"status": "completed"
|
||
},
|
||
{
|
||
"source": "vedomosti",
|
||
"processedItems": 7,
|
||
"totalItemsInDb": 1317,
|
||
"status": "completed"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 3. Получение списка доступных парсеров
|
||
|
||
```http
|
||
GET /api/admin/parsers
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Список парсеров получен",
|
||
"data": ["kapital", "kursiv", "lsm", "rbc", "vedomosti"]
|
||
}
|
||
```
|
||
|
||
### 4. Получение информации о парсерах
|
||
|
||
```http
|
||
GET /api/admin/parsers/info
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Информация о парсерах получена",
|
||
"data": {
|
||
"totalParsers": 5,
|
||
"availableParsers": ["kapital", "kursiv", "lsm", "rbc", "vedomosti"],
|
||
"totalItems": 1317,
|
||
"sourceStatistics": {
|
||
"Kursiv Media": 300,
|
||
"Kapital.kz": 250,
|
||
"LSM.kz": 200,
|
||
"РБК": 300,
|
||
"Ведомости": 200
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5. Проверка существования парсера
|
||
|
||
```http
|
||
GET /api/admin/parsers/exists/{sourceName}
|
||
```
|
||
|
||
**Пример:**
|
||
|
||
```javascript
|
||
fetch('/api/admin/parsers/exists/kursiv');
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Проверка завершена",
|
||
"data": true
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 HealthCheckController - Мониторинг системы
|
||
|
||
**Базовый URL**: `/api/health`
|
||
|
||
### 1. Базовая проверка состояния
|
||
|
||
```http
|
||
GET /api/health
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Сервис работает",
|
||
"data": {
|
||
"status": "UP",
|
||
"service": "RSS Parser System",
|
||
"timestamp": 1705312500000,
|
||
"details": "Enabled - runs every 30 minutes"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. Проверка подключения к MongoDB
|
||
|
||
```http
|
||
GET /api/health/mongodb
|
||
```
|
||
|
||
**Ответ (успех):**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "MongoDB подключение успешно",
|
||
"data": {
|
||
"status": "UP",
|
||
"service": "MongoDB подключение успешно",
|
||
"timestamp": 1705312500000,
|
||
"details": "Всего записей: 1317"
|
||
}
|
||
}
|
||
```
|
||
|
||
**Ответ (ошибка):**
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "Ошибка подключения к MongoDB",
|
||
"data": {
|
||
"status": "DOWN",
|
||
"service": "Ошибка подключения к MongoDB: Connection refused",
|
||
"timestamp": 1705312500000,
|
||
"suggestion": "Проверьте учетные данные в application.properties"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. Информация о планировщике
|
||
|
||
```http
|
||
GET /api/health/scheduler
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Информация о планировщике получена",
|
||
"data": {
|
||
"schedulerEnabled": true,
|
||
"cronExpression": "0 0/30 * * * ?",
|
||
"description": "Запуск каждые 30 минут (в 0 и 30 минут каждого часа)",
|
||
"nextRun": "Следующий запуск будет в ближайшие 0 или 30 минут часа",
|
||
"activeParsers": ["kapital", "kursiv", "lsm", "rbc", "vedomosti"],
|
||
"totalParsers": 5,
|
||
"sources": ["Kursiv Media", "Kapital.kz", "LSM.kz", "РБК", "Ведомости"]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. Общая информация о системе
|
||
|
||
```http
|
||
GET /api/health/system
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Информация о системе получена",
|
||
"data": {
|
||
"parsers": {
|
||
"total": 5,
|
||
"available": ["kapital", "kursiv", "lsm", "rbc", "vedomosti"]
|
||
},
|
||
"data": {
|
||
"totalItems": 1317,
|
||
"sourceStatistics": {
|
||
"Kursiv Media": 300,
|
||
"Kapital.kz": 250,
|
||
"LSM.kz": 200,
|
||
"РБК": 300,
|
||
"Ведомости": 200
|
||
}
|
||
},
|
||
"system": {
|
||
"javaVersion": "17.0.2",
|
||
"osName": "Linux",
|
||
"osVersion": "5.4.0-74-generic",
|
||
"uptime": 1705312500000
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5. Проверка состояния парсеров
|
||
|
||
```http
|
||
GET /api/health/parsers
|
||
```
|
||
|
||
**Ответ:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Проверка парсеров завершена",
|
||
"data": {
|
||
"totalParsers": 5,
|
||
"availableParsers": ["kapital", "kursiv", "lsm", "rbc", "vedomosti"],
|
||
"status": "UP",
|
||
"message": "Все парсеры доступны"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 Примеры использования для фронтенда
|
||
|
||
### React/JavaScript примеры
|
||
|
||
```javascript
|
||
// Сервис для работы с API
|
||
class NewsApiService {
|
||
constructor(baseUrl = '') {
|
||
this.baseUrl = baseUrl;
|
||
}
|
||
|
||
// Получить новости с фильтрацией
|
||
async getNews(filters = {}) {
|
||
const params = new URLSearchParams();
|
||
|
||
if (filters.sourceName) params.append('sourceName', filters.sourceName);
|
||
if (filters.startDate) params.append('startDate', filters.startDate);
|
||
if (filters.endDate) params.append('endDate', filters.endDate);
|
||
if (filters.page !== undefined) params.append('page', filters.page);
|
||
if (filters.size) params.append('size', filters.size);
|
||
if (filters.sort) params.append('sort', filters.sort);
|
||
|
||
const response = await fetch(`${this.baseUrl}/api/items?${params}`);
|
||
return response.json();
|
||
}
|
||
|
||
// Получить статистику
|
||
async getStats() {
|
||
const response = await fetch(`${this.baseUrl}/api/items/stats`);
|
||
return response.json();
|
||
}
|
||
|
||
// Получить источники
|
||
async getSources() {
|
||
const response = await fetch(`${this.baseUrl}/api/items/sources`);
|
||
return response.json();
|
||
}
|
||
|
||
// Запустить парсер (админ функция)
|
||
async runParser(sourceName) {
|
||
const response = await fetch(
|
||
`${this.baseUrl}/api/admin/parsers/parse/${sourceName}`,
|
||
{
|
||
method: 'POST',
|
||
}
|
||
);
|
||
return response.json();
|
||
}
|
||
|
||
// Запустить все парсеры (админ функция)
|
||
async runAllParsers() {
|
||
const response = await fetch(
|
||
`${this.baseUrl}/api/admin/parsers/parse/all`,
|
||
{
|
||
method: 'POST',
|
||
}
|
||
);
|
||
return response.json();
|
||
}
|
||
|
||
// Проверить состояние системы
|
||
async getHealthStatus() {
|
||
const response = await fetch(`${this.baseUrl}/api/health`);
|
||
return response.json();
|
||
}
|
||
}
|
||
|
||
// Использование
|
||
const apiService = new NewsApiService();
|
||
|
||
// Получить последние новости
|
||
const news = await apiService.getNews({
|
||
page: 0,
|
||
size: 20,
|
||
sort: 'publishedAt,desc',
|
||
});
|
||
|
||
// Получить новости от конкретного источника
|
||
const kursivNews = await apiService.getNews({
|
||
sourceName: 'Kursiv Media',
|
||
page: 0,
|
||
size: 10,
|
||
});
|
||
|
||
// Получить новости за последнюю неделю
|
||
const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
|
||
const recentNews = await apiService.getNews({
|
||
startDate: weekAgo,
|
||
sort: 'publishedAt,desc',
|
||
});
|
||
```
|
||
|
||
### Vue.js примеры
|
||
|
||
```javascript
|
||
// composable для работы с API
|
||
export function useNewsApi() {
|
||
const baseUrl = '';
|
||
|
||
const getNews = async (filters = {}) => {
|
||
const params = new URLSearchParams();
|
||
Object.entries(filters).forEach(([key, value]) => {
|
||
if (value !== undefined && value !== null) {
|
||
params.append(key, value);
|
||
}
|
||
});
|
||
|
||
const response = await fetch(`${baseUrl}/api/items?${params}`);
|
||
return response.json();
|
||
};
|
||
|
||
const getStats = async () => {
|
||
const response = await fetch(`${baseUrl}/api/items/stats`);
|
||
return response.json();
|
||
};
|
||
|
||
const getSources = async () => {
|
||
const response = await fetch(`${baseUrl}/api/items/sources`);
|
||
return response.json();
|
||
};
|
||
|
||
return {
|
||
getNews,
|
||
getStats,
|
||
getSources,
|
||
};
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 Важные замечания
|
||
|
||
1. **Пагинация**: Все эндпоинты для получения данных поддерживают пагинацию через параметры `page` и `size`.
|
||
|
||
2. **Сортировка**: По умолчанию новости сортируются по дате публикации (новые сначала). Можно изменить через параметр `sort`.
|
||
|
||
3. **Фильтрация**: Поддерживается фильтрация по источнику и диапазону дат.
|
||
|
||
4. **Формат дат**: Используйте ISO 8601 формат для дат (например: "2024-01-15T10:30:00").
|
||
|
||
5. **Обработка ошибок**: Все ответы содержат поле `success` для проверки успешности операции.
|
||
|
||
6. **Административные функции**: Эндпоинты `/api/admin/parsers/*` предназначены для административных функций.
|
||
|
||
7. **Мониторинг**: Используйте эндпоинты `/api/health/*` для проверки состояния системы.
|
||
|
||
---
|
||
|
||
## 🔄 Миграция с старого API
|
||
|
||
Если у вас был код, использующий старый `ParserController`, вот соответствие эндпоинтов:
|
||
|
||
| Старый эндпоинт | Новый эндпоинт |
|
||
| ---------------------------------- | ----------------------------------------- |
|
||
| `POST /api/parser/parse/kursiv` | `POST /api/admin/parsers/parse/kursiv` |
|
||
| `POST /api/parser/parse/kapital` | `POST /api/admin/parsers/parse/kapital` |
|
||
| `POST /api/parser/parse/lsm` | `POST /api/admin/parsers/parse/lsm` |
|
||
| `POST /api/parser/parse/rbc` | `POST /api/admin/parsers/parse/rbc` |
|
||
| `POST /api/parser/parse/vedomosti` | `POST /api/admin/parsers/parse/vedomosti` |
|
||
| `POST /api/parser/parse/all` | `POST /api/admin/parsers/parse/all` |
|
||
| `GET /api/parser/items` | `GET /api/items` |
|
||
| `GET /api/parser/stats` | `GET /api/items/stats` |
|
||
| `GET /api/parser/health` | `GET /api/health` |
|
||
| `GET /api/parser/health/mongodb` | `GET /api/health/mongodb` |
|
||
| `GET /api/parser/scheduler/info` | `GET /api/health/scheduler` |
|