Модуль 11 · Урок 43 із 58
REST API contract: resources, pagination і Problem Details
REST API стає передбачуваним, коли URL називає resource, HTTP semantics лишаються стандартними, collection має стабільну pagination, а errors і compatibility описані як перевірний контракт, а не набір випадкових JSON-відповідей.
Безпечна HTTP-практика модуля 11
Пакет містить synthetic fixtures, loopback-only HTTP server, bounded urllib client, Problem Details і contract tests. Тести виконують реальні request/response лише на 127.0.0.1 без Internet, персональних чи production-даних, credentials і production endpoints.
Resource — не назва функції
Замість /createTask, /getTasks і /deleteTask resource-oriented API використовує collection /tasks та member /tasks/{task_id}, а intent передає method. Це не косметика: generic tooling, caching, observability і authorization отримують стабільну модель.
| Intent | Request | Типовий result |
|---|---|---|
| List | GET /tasks | 200 + collection representation |
| Create | POST /tasks | 201 + Location |
| Read | GET /tasks/{id} | 200 або 404 |
| Replace | PUT /tasks/{id} | 200/204 за contract |
| Delete | DELETE /tasks/{id} | 204 за contract |
Collection потребує deterministic pagination
API фіксує sort order і tie-breaker. Offset pagination проста, але concurrent inserts можуть зрушувати rows. Cursor/keyset pagination кодує позицію після стабільної пари, наприклад (created_at, id). Cursor є opaque для клієнта, але server має валідувати його version, signature/shape і filter compatibility.
{
"items": [{"id": 41, "title": "Synthetic task"}],
"next_cursor": "opaque-training-cursor",
"has_more": true
}Response contract визначає maximum limit, default limit, empty collection, filter syntax і поведінку invalid cursor.
Problem Details уніфікує errors
RFC 9457 визначає application/problem+json і базові members type, status, title, detail, instance. HTTP status лишається authoritative для generic software; detail допомагає людині, але client не повинен парсити його як machine contract. Для machine-readable domain data додають typed extensions.
{
"type": "https://api.example.test/problems/invalid-cursor",
"title": "Invalid pagination cursor",
"status": 400,
"detail": "Request a fresh collection page.",
"instance": "/problems/req-7f2a"
}Не виносьте internals у detail
Stack trace, SQL, filesystem path, secret, account existence або service topology можуть перетворити зручний error на витік. Public detail проходить окрему security review.
Idempotency захищає create workflow
Коли client не знає, чи POST був оброблений до network failure, повтор може створити duplicate. Узгоджений Idempotency-Key дозволяє server зберегти outcome для ключа, звірити request fingerprint і повернути той самий logical result. Scope, TTL, collision behavior і storage atomicity є частиною contract.
Ключ не робить будь-який action безпечним автоматично: email, payment або webhook потребують власної deduplication/outbox boundary.
API еволюціонує additive-first
Новий optional response field зазвичай сумісніший, ніж перейменування або зміна type. Clients мають ігнорувати документовані unknown fields, а server — не змінювати semantics існуючого field потай. Breaking change потребує version/migration policy, telemetry використання й sunset communication.
Практичний pack запускає loopback HTTP server на випадковому локальному port і доводить реальний request/response без зовнішньої мережі. Він не заявляє production readiness, load capacity або security certification.
Методичні джерела
Урок, сценарії, пояснення й вправи створені SEOWORK. Посилання ведуть на стандарти та авторитетну офіційну документацію.
Закріпіть матеріал уроку
Три сценарні питання. Для зарахування уроку потрібно дати щонайменше дві правильні відповіді.