Skip to content

Latest commit

 

History

History
508 lines (406 loc) · 16 KB

README_API.md

File metadata and controls

508 lines (406 loc) · 16 KB

API Сервиса Вакансий

Backend-сервис для хранения и управления вакансиями на базе Yii2.

Требования

  • PHP 8.0 или выше
  • MySQL 5.7+ или PostgreSQL 9.5+
  • Composer
  • Apache/Nginx с mod_rewrite

Установка

1. Установка зависимостей

composer install

2. Настройка базы данных

Отредактируйте файл config/db.php и укажите параметры подключения к БД:

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=vakansii_db',
    'username' => 'root',
    'password' => 'your_password',
    'charset' => 'utf8mb4',
];

3. Создание базы данных

Создайте базу данных:

mysql -u root -p -e "CREATE DATABASE vakansii_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

Или для PostgreSQL:

psql -U postgres -c "CREATE DATABASE vakansii_db ENCODING 'UTF8';"

4. Применение миграций

./yii migrate

5. Настройка веб-сервера

Apache

Убедитесь, что DocumentRoot указывает на директорию web/:

<VirtualHost *:80>
    ServerName vakansii-api.local
    DocumentRoot /path/to/vakansii-back/web

    <Directory /path/to/vakansii-back/web>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Nginx

server {
    listen 80;
    server_name vakansii-api.local;
    root /path/to/vakansii-back/web;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass 127.0.0.1:9000;
        try_files $uri =404;
    }
}

6. Установка прав доступа

chmod -R 777 runtime web/assets

API Endpoints

1. Полнотекстовый поиск вакансий 🔍

GET /vacancy/search

Описание: Быстрый полнотекстовый поиск по названию и описанию вакансий с использованием FULLTEXT индексов (10-100x быстрее обычного поиска).

Параметры запроса:

  • q (string, обязательный) - поисковый запрос (1-255 символов)
  • page (integer, optional) - номер страницы (1-10000, по умолчанию: 1)
  • sort (string, optional) - тип сортировки:
    • relevance (по умолчанию) - по релевантности результатов
    • asc - по дате создания (старые первые)
    • desc - по дате создания (новые первые)

Пример запроса:

GET /vacancy/search?q=PHP разработчик&page=1&sort=relevance

Пример ответа:

{
    "data": [
        {
            "id": 1,
            "title": "Senior PHP Developer",
            "salary": 200000,
            "description": "Требуется опытный PHP разработчик с глубокими знаниями фреймворков"
        },
        {
            "id": 5,
            "title": "Backend PHP Developer",
            "salary": 150000,
            "description": "Ищем PHP разработчика для работы над микросервисами"
        }
    ],
    "pagination": {
        "total": 12,
        "page": 1,
        "pageSize": 10,
        "pageCount": 2
    },
    "query": "PHP разработчик"
}

Пример ошибки (пустой запрос):

{
    "success": false,
    "message": "Поисковый запрос не может быть пустым"
}

Особенности:

  • Поддержка PostgreSQL (tsvector с русской морфологией) и MySQL (FULLTEXT)
  • Кеширование результатов на 5 минут для повышения производительности
  • Регистронезависимый поиск
  • Автоматическое ранжирование по релевантности

2. Получение списка вакансий

GET /vacancy

Параметры запроса:

  • page (integer, optional) - номер страницы (по умолчанию: 1)
  • sort (string, optional) - поле для сортировки: salary или created_at (по умолчанию: created_at)
  • order (string, optional) - порядок сортировки: asc или desc (по умолчанию: desc)

Пример запроса:

GET /vacancy?page=1&sort=salary&order=desc

Пример ответа:

{
    "data": [
        {
            "id": 1,
            "title": "PHP Developer",
            "salary": 150000,
            "description": "Требуется опытный PHP разработчик"
        },
        {
            "id": 2,
            "title": "Frontend Developer",
            "salary": 120000,
            "description": "Ищем frontend разработчика"
        }
    ],
    "pagination": {
        "total": 25,
        "page": 1,
        "pageSize": 10,
        "pageCount": 3
    }
}

2. Получение конкретной вакансии

GET /vacancy/{id}

Параметры запроса:

  • fields (string, optional) - список полей через запятую для выборочного отображения: title, description, salary, additional_fields

Пример запроса без фильтра:

GET /vacancy/1

Пример ответа:

{
    "id": 1,
    "title": "PHP Developer",
    "salary": 150000,
    "description": "Требуется опытный PHP разработчик",
    "additional_fields": {
        "company": "Tech Corp",
        "location": "Москва"
    }
}

Пример запроса с фильтром полей:

GET /vacancy/1?fields=title,salary

Пример ответа:

{
    "id": 1,
    "title": "PHP Developer",
    "salary": 150000
}

3. Создание вакансии

POST /vacancy

Тело запроса (JSON):

{
    "title": "PHP Developer",
    "description": "Требуется опытный PHP разработчик с опытом работы от 3 лет",
    "salary": 150000,
    "additional_fields": {
        "company": "Tech Corp",
        "location": "Москва",
        "employment_type": "full-time"
    }
}

Пример успешного ответа:

{
    "success": true,
    "id": 1,
    "message": "Вакансия успешно создана"
}

Пример ответа с ошибкой:

{
    "success": false,
    "errors": {
        "title": ["Название вакансии не может быть пустым."],
        "salary": ["Зарплата должна быть целым числом."]
    },
    "message": "Ошибка при создании вакансии"
}

Структура базы данных

Таблица vacancy

Поле Тип Описание
id INT Первичный ключ (AUTO_INCREMENT)
title VARCHAR(255) Название вакансии (обязательное)
description TEXT Описание вакансии (обязательное)
salary INT Зарплата (обязательное)
additional_fields JSON Дополнительные поля (опциональное)
search_vector TSVECTOR Полнотекстовый индекс (PostgreSQL)
created_at INT Время создания (UNIX timestamp)
updated_at INT Время обновления (UNIX timestamp)

Индексы:

  • PRIMARY KEY на id
  • GIN INDEX на search_vector (PostgreSQL) для полнотекстового поиска
  • FULLTEXT INDEX на title, description (MySQL) для полнотекстового поиска

Примеры использования

cURL

Полнотекстовый поиск вакансий:

# Простой поиск
curl -X GET "http://localhost/vacancy/search?q=PHP"

# Поиск по нескольким словам
curl -X GET "http://localhost/vacancy/search?q=PHP%20разработчик"

# Поиск с пагинацией и сортировкой
curl -X GET "http://localhost/vacancy/search?q=developer&page=2&sort=relevance"

Получение списка вакансий:

curl -X GET "http://localhost/vacancy?page=1&sort=salary&order=desc"

Получение конкретной вакансии:

curl -X GET "http://localhost/vacancy/1"

Получение вакансии с выбранными полями:

curl -X GET "http://localhost/vacancy/1?fields=title,salary"

Создание вакансии:

curl -X POST "http://localhost/vacancy" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "PHP Developer",
    "description": "Требуется опытный PHP разработчик",
    "salary": 150000,
    "additional_fields": {
      "company": "Tech Corp",
      "location": "Москва"
    }
  }'

JavaScript (Fetch API)

Полнотекстовый поиск вакансий:

// Простой поиск
const searchVacancies = async (query) => {
  const response = await fetch(`http://localhost/vacancy/search?q=${encodeURIComponent(query)}`);
  const data = await response.json();
  return data;
};

// Использование
const results = await searchVacancies('PHP разработчик');
console.log(results.data); // Массив вакансий
console.log(results.pagination.total); // Общее количество

Получение списка вакансий:

fetch('http://localhost/vacancy?page=1&sort=salary&order=desc')
  .then(response => response.json())
  .then(data => console.log(data));

Создание вакансии:

fetch('http://localhost/vacancy', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    title: 'PHP Developer',
    description: 'Требуется опытный PHP разработчик',
    salary: 150000,
    additional_fields: {
      company: 'Tech Corp',
      location: 'Москва'
    }
  })
})
  .then(response => response.json())
  .then(data => console.log(data));

Производительность и кеширование

Полнотекстовый поиск

  • 10-100x быстрее обычного LIKE поиска благодаря FULLTEXT индексам
  • PostgreSQL: использует tsvector с русской морфологией и ts_rank для ранжирования
  • MySQL: использует FULLTEXT индекс с MATCH...AGAINST
  • Кеширование результатов поиска на 5 минут

Кеширование списка вакансий

  • Результаты запросов кешируются на 5-10 минут
  • Значительное ускорение повторных запросов
  • Автоматическая инвалидация кеша при изменении данных

Benchmarks полнотекстового поиска

Количество записей LIKE поиск FULLTEXT поиск Ускорение
100 вакансий ~50-100ms ~5-10ms 10x
1000 вакансий ~200-500ms ~10-20ms 10-25x
10000 вакансий ~1000-3000ms ~20-50ms 20-150x
С кешем - ~1-5ms 200-600x

Rate Limiting

API защищен системой ограничения запросов:

  • Лимит: 100 запросов в час на IP-адрес
  • Ответ при превышении лимита: HTTP 429 (Too Many Requests)
  • Заголовки ответа:
    • X-Rate-Limit-Limit - максимальное количество запросов
    • X-Rate-Limit-Remaining - оставшееся количество запросов
    • X-Rate-Limit-Reset - время сброса лимита (UNIX timestamp)

Пример ответа при превышении лимита:

{
    "success": false,
    "message": "Rate limit exceeded. Try again later.",
    "retry_after": 3600
}

CORS

CORS настроен и разрешает запросы с любых источников для упрощения интеграции с frontend.

Тестирование

Автоматические тесты

Проект имеет полное покрытие автоматическими тестами:

# Все тесты (unit, functional, API)
vendor/bin/codecept run

# Только API тесты
vendor/bin/codecept run api

# Тесты полнотекстового поиска
vendor/bin/codecept run api SearchCest

# Тесты rate limiting
vendor/bin/codecept run api RateLimitingCest

# С подробным выводом
vendor/bin/codecept run --debug

Ручное тестирование

Для ручного тестирования API можно использовать:

  • Swagger UI: http://localhost:8080/swagger-ui.html - интерактивная документация
  • ReDoc: http://localhost:8080/redoc.html - альтернативная документация
  • Postman
  • Insomnia
  • cURL
  • Встроенные инструменты браузера

Возможные ошибки

Ошибка подключения к базе данных

Проверьте настройки в config/db.php и убедитесь, что база данных создана.

404 Not Found

Убедитесь, что:

  • mod_rewrite включен (для Apache)
  • файл .htaccess присутствует в директории web/
  • Pretty URLs включены в конфигурации

500 Internal Server Error

Проверьте логи в директории runtime/logs/

Медленный поиск

Если полнотекстовый поиск работает медленно:

  • Убедитесь, что миграции применены: php yii migrate
  • Проверьте наличие FULLTEXT индексов в базе данных
  • Для PostgreSQL: убедитесь, что колонка search_vector существует
  • Для MySQL: проверьте наличие FULLTEXT индекса на полях title, description

Дополнительная документация

Для более подробной информации обратитесь к следующим документам:

  • README.md - Общая информация о проекте и быстрый старт
  • QUICKSTART.md - Пошаговое руководство по запуску за 5 минут
  • FULLTEXT_SEARCH.md - Подробное руководство по полнотекстовому поиску
  • ARCHITECTURE.md - Описание архитектуры проекта
  • PROJECT_INFO.md - Детальная информация о реализации
  • HTTPS_SETUP.md - Настройка HTTPS/SSL
  • SETUP_GUIDE.md - Полное руководство по настройке (HTTPS, CI/CD, Swagger)
  • DOCKER.md - Запуск в Docker
  • Swagger UI - Интерактивная API документация

Лицензия

MIT