Junior: питання на співбесіді з теми «Документація й контракти»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
5 питань
OpenAPI (раніше Swagger) - стандартний машиночитний формат опису HTTP API у YAML чи JSON: ендпойнти, параметри, тіла запитів і відповідей, коди статусу, автентифікація.
openapi: 3.1.0
info:
title: Vacancies API
version: 1.0.0
paths:
/vacancies/{id}:
get:
summary: Отримати вакансію
parameters:
- name: id
in: path
required: true
schema: { type: integer }
responses:
'200':
description: Вакансія
content:
application/json:
schema: { $ref: '#/components/schemas/Vacancy' }
'404':
description: Не знайдено
components:
schemas:
Vacancy:
type: object
required: [id, title]
properties:
id: { type: integer }
title: { type: string }
salary_from: { type: [integer, 'null'] }
Що дає специфікація, крім документації:
- інтерактивна документація - Swagger UI, Redoc, Scalar, Stoplight Elements з кнопкою «спробувати запит»;
- генерація клієнтів - типізовані SDK для TypeScript, PHP, мобільних застосунків;
- моки - фронтенд працює з фейковим сервером до готовності бекенду;
- тести й валідація - перевірка, що реальні відповіді відповідають опису;
- лінтинг - автоматична перевірка стилю й помилок у дизайні;
- виявлення змін, що ламають клієнтів, - порівняння версій специфікації в CI;
- імпорт у Postman, Insomnia, Bruno, API-шлюзи.
Версії:
- 3.0 - найпоширеніша в старих інструментах;
- 3.1 (2021) - повна сумісність із JSON Schema 2020-12;
- 3.2 (вересень 2025) - зворотно сумісне розширення 3.1: потокові медіатипи (SSE, JSON Lines), нові поля для тегів, метод
QUERYтощо.
Для нових проєктів - 3.1 чи 3.2, з перевіркою, що потрібні інструменти їх підтримують.
Головна цінність - єдине джерело правди про контракт між бекендом і клієнтами, замість вікі-сторінок, які розходяться з кодом через тиждень.
У Laravel специфікацію найчастіше генерують з коду (Scramble, Scribe), а не пишуть вручну.
Code-first - спершу пишеться код, специфікація генерується з нього (атрибутами, аналізом коду):
контролери й ресурси Laravel → Scramble/Scribe → openapi.json → документація
Design-first - спершу пишеться специфікація (контракт), її обговорюють і погоджують, а потім за нею пишуть код і клієнтів:
openapi.yaml (рев'ю) → моки для фронтенду → реалізація бекенду → перевірка відповідності
Переваги code-first:
- специфікація не розходиться з кодом - вона з нього й береться;
- швидкий старт, мало додаткової роботи;
- зручно для невеликих команд, де бекенд і фронтенд пишуть ті самі люди.
Недоліки code-first:
- дизайн API формується реалізацією: назви полів і структура відповідей відображають внутрішню модель (колонки таблиць), а не потреби клієнтів;
- обговорити API можна лише після того, як його написано;
- генератор бачить не все: деталі на кшталт можливих помилок чи прикладів доводиться доповнювати.
Переваги design-first:
- контракт - до коду: фронтенд, мобільна команда й партнери погоджують API заздалегідь і працюють паралельно з моками;
- кращий дизайн: API проєктують з боку споживача, з рев'ю, як код;
- генерація серверних заготовок і валідація запитів за специфікацією.
Недоліки design-first:
- специфікацію треба підтримувати вручну - і перевіряти, що реалізація їй відповідає (тести контракту, валідація відповідей у тестах), інакше вона застаріває;
- більше процесу й інструментів.
Що обирають на практиці:
- внутрішнє API одного продукту (Laravel + SPA однієї команди) - code-first зі Scramble: мінімум зусиль, завжди актуально;
- публічне API, партнерські інтеграції, кілька команд-споживачів - design-first або гібрид: дизайн погоджується в специфікації, а згенерована з коду специфікація порівнюється з погодженою в CI;
- будь-який підхід виграє від лінтингу специфікації і перевірки змін, що ламають клієнтів, у CI.
Докладніше в документації: Документація OpenAPI для початківців
Scramble генерує специфікацію OpenAPI з коду Laravel автоматично, без анотацій над кожним методом. Він аналізує:
- маршрути - шляхи, методи, параметри маршруту й прив'язку моделей;
- валідацію - правила з Form Request чи
$request->validate()стають описом тіла запиту й параметрів (required|email|max:255→ обов'язковий рядок формату email); - відповіді - API-ресурси (
JsonResource), повернені моделі, пагінацію,response()->json(...); - помилки - 422 для валідації, 404 для прив'язки моделей, 403 для авторизації, 401 для автентифікації.
composer require dedoc/scramble
Після встановлення документація доступна за адресою /docs/api (інтерфейс на основі Stoplight Elements), а сама специфікація - /docs/api.json.
Доповнення там, де аналізу коду недостатньо:
/**
* Список вакансій.
*
* Повертає опубліковані вакансії, найновіші першими.
*/
public function index(IndexVacancyRequest $request)
{
// ...
}
PHPDoc-коментар стає описом операції. Для складних випадків - атрибути Scramble й розширення.
Що варто налаштувати:
- доступ: за замовчуванням документація відкрита лише в локальному оточенні, у продакшені доступ визначає gate
viewApiDocs; - які маршрути документувати (за замовчуванням - з префіксом
api); - автентифікація: опис схеми (Bearer-токен Sanctum), щоб кнопка «спробувати» працювала;
- експорт:
php artisan scramble:exportзаписує специфікацію у файл - для генерації клієнтів і перевірок у CI.
Альтернатива - Scribe: генерує документацію й колекції Postman, бере опис з анотацій і може робити справжні запити до ендпойнтів, щоб отримати приклади відповідей.
Обмеження автоматичної генерації:
- точність залежить від коду: динамічні масиви в
toArray(), умовна логіка, дані з сервісів можуть описатися неточно - результат треба переглядати; - якість опису - на вас: назви полів, приклади, пояснення бізнес-правил генератор не придумає;
- вбудовані JSON:API-ресурси Laravel 13 - новий формат; варто перевірити, що версія генератора їх підтримує.
Laravel має набір перевірок для JSON-відповідей. Головне - обирати перевірку під те, що саме гарантує API.
it('returns a vacancy', function () {
$vacancy = Vacancy::factory()->create(['title' => 'Laravel Developer', 'salary_from' => 3000]);
$this->getJson("/api/vacancies/{$vacancy->id}")
->assertOk()
->assertJsonPath('data.title', 'Laravel Developer')
->assertJsonPath('data.salary_from', 3000)
->assertJsonStructure([
'data' => ['id', 'title', 'salary_from', 'company' => ['id', 'name']],
]);
});
Основні методи:
| Метод | Що перевіряє |
|---|---|
assertJson([...]) |
відповідь містить ці дані (інші поля дозволені) |
assertExactJson([...]) |
відповідь дорівнює цьому JSON |
assertJsonPath('data.title', '...') |
значення за шляхом |
assertJsonStructure([...]) |
наявність ключів (без значень) |
assertExactJsonStructure([...]) |
ключі - і жодних зайвих |
assertJsonCount(20, 'data') |
кількість елементів |
assertJsonMissingPath('data.password') |
поля немає |
assertJsonValidationErrors(['email']) |
помилки валідації для полів |
Методи запиту: getJson, postJson, patchJson, deleteJson - автоматично додають Accept: application/json, тож помилки валідації приходять як JSON 422, а не редирект.
Що варто перевіряти в API-тестах:
- контракт: структура відповіді й типи - те, на що покладаються клієнти;
- приховані поля:
assertJsonMissingPath('data.password_hash')- захист від випадкового витоку при зміні ресурсу; - коди статусу для кожного сценарію: 201 при створенні, 422 при помилках, 403 для чужого ресурсу, 404 для неіснуючого;
- авторизацію: запит від іншого користувача (
actingAs($stranger)) - найчастіше забута перевірка; - пагінацію й фільтри:
assertJsonCount, перевірка, що фільтр справді відсікає записи.
Пастки:
assertJsonне перевіряє відсутність полів - нове випадкове поле в ресурсі тест не помітить. Для захисту контракту -assertExactJsonStructureабо перевірка відповідності специфікації OpenAPI;- типи:
assertJsonPath('data.price', 100)і'100.00'- різні значення; рішення про формат грошей має бути зафіксоване тестом; - дати порівнюють у форматі, який віддає API (ISO 8601 з поясом), а не як об'єкти Carbon.
Для складних перевірок - fluent-API assertJson(fn (AssertableJson $json) => ...).
Згенерований перелік ендпойнтів з параметрами - лише довідник. Розробник, що інтегрується з API, має відповіді на питання «з чого почати» і «що робити, коли щось пішло не так».
1. Швидкий старт: як отримати ключ, перший запит, який можна скопіювати й виконати за хвилину:
curl https://api.example.com/v1/vacancies?city=kyiv \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
2. Автентифікація: як отримати й оновити токен, термін дії, області доступу (scopes).
3. Приклади - для кожного запиту й відповіді. Реалістичні дані, а не "string" і 0. В OpenAPI - поля example/examples у схемах і медіатипах. Кілька прикладів для різних сценаріїв (вакансія із зарплатою і без).
4. Помилки - не менш детально, ніж успіх:
- формат помилки (Problem Details чи власний) з прикладами;
- коди помилок бізнес-логіки й що з ними робити (
insufficient_balance- поповнити рахунок); - які помилки тимчасові й можна повторити (429, 503), а які ні.
5. Загальні правила API - один раз для всіх ендпойнтів:
- пагінація, фільтрація, сортування;
- формати дат, грошей, ідентифікаторів;
- ліміти частоти й заголовки, що їх показують;
- ідемпотентність і повтори;
- версіонування й політика змін.
6. Сценарії (гайди): типові задачі, що складаються з кількох запитів - «створити замовлення й оплатити», «синхронізувати каталог». Довідник ендпойнтів їх не пояснює.
7. Журнал змін (changelog) і дати застарівання.
8. SDK і колекції: офіційні клієнти, колекція Postman/Bruno, посилання на специфікацію OpenAPI для генерації власних клієнтів.
Якість, яку легко перевірити:
- новий розробник робить перший успішний запит без запитань до команди;
- кожен ендпойнт має приклад відповіді й перелік можливих помилок;
- приклади в документації перевіряються автоматично (контрактні тести, валідація за специфікацією) - інакше вони застаріють першими.
Інтерактивність: кнопка «спробувати» в документації (Swagger UI, Scalar, Stoplight Elements) з тестовим оточенням (sandbox) пришвидшує інтеграцію - але ніколи з продакшен-даними.
Докладніше в документації: Документація OpenAPI для початківців