Из чего состоит контракт API между сервером и клиентом?

Ответ

Контракт API — это формальное соглашение, которое точно определяет, как клиентское приложение (например, фронтенд или мобильное приложение) должно взаимодействовать с серверным API. QA-инженер использует этот контракт как источник истины для создания тестов.

Ключевые компоненты API-контракта:

  1. Базовый URL и эндпоинты: Адреса для доступа к ресурсам (например, https://api.example.com/v1/users).
  2. HTTP-методы: Действия, которые можно выполнить с ресурсом: GET (получить), POST (создать), PUT/PATCH (обновить), DELETE (удалить).
  3. Параметры запроса:
    • Path parameters: Часть URL (/users/{userId}).
    • Query parameters: Параметры после ? в URL (?sort=asc&limit=10).
    • Заголовки (Headers): Мета-информация (Authorization, Content-Type).
  4. Тело запроса (Request Body): Данные, отправляемые на сервер (обычно в формате JSON или XML), включая обязательные и опциональные поля, типы данных и ограничения (валидация).
  5. Тело ответа (Response Body): Структура и формат данных, возвращаемых сервером.
  6. Коды состояния HTTP (Status Codes): Стандартные ответы: 2xx (успех), 4xx (ошибка клиента, например, 400 Bad Request, 404 Not Found), 5xx (ошибка сервера).
  7. Схемы данных (Data Schemas): Точное определение структуры объектов запроса и ответа (используется JSON Schema, OpenAPI Schema).
  8. Аутентификация и авторизация: Описание метода доступа (API Key, OAuth 2.0, JWT).
  9. Скоростные ограничения (Rate Limiting): Правила по количеству запросов в единицу времени.

Пример фрагмента контракта в формате OpenAPI (Swagger), на основе которого строятся тесты:

openapi: 3.0.0
paths:
  /users:
    post:
      summary: Create a new user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - name
              properties:
                email:
                  type: string
                  format: email
                name:
                  type: string
                  minLength: 2
      responses:
        '201': # Код состояния
          description: User created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          description: Invalid input data

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
          example: 42
        email:
          type: string
        name:
          type: string

Для QA этот контракт критически важен: он позволяет автоматически генерировать тесты на валидацию схемы (с помощью инструментов вроде Dredd или Schemathesis), проверять граничные значения и гарантировать, что любые изменения API на стороне сервера не сломают клиент, если контракт остается прежним (тестирование на совместимость).

Ответ 18+ 🔞

Давай разжую эту тему про API-контракты, чтобы было понятно даже тому, кто только вчера узнал, что интернет — это не только порнохаб.

Представь себе, что ты пришёл в ресторан. Меню — это и есть тот самый контракт API, ёпта. Там чётко написано: «Борщ — 300 грамм, со сметаной, стоит 250 рублей». Ты, как клиент (фронтенд), делаешь заказ (отправляешь запрос). Если кухня (сервер) принесёт тебе холодный борщ без сметаны — это пиздец, нарушение контракта. Ты имеешь полное право орать «Официант!» и тыкать пальцем в меню. Вот QA-инженер — это такой дохуя дотошный гость, который проверяет, соответствует ли каждое блюдо в меню тому, что приносят на стол. И не просто смотрит, а тыкает в него вилкой, нюхает и меряет температуру термометром, блядь.

Из чего этот контракт состоит, чтобы не было мухлёжа:

  1. Адрес забегаловки и столик (Базовый URL и эндпоинты). Не придешь же ты в «Макдак» и не спросишь суши? https://api.borshch.com/v1/stolovaya — вот куда стучаться.
  2. Что ты хочешь сделать (HTTP-методы). GET — «дай мне борщ», POST — «свари мне новый борщ», PUT — «пересоли этот борщ, пожалуйста», DELETE — «убери этот борщ с моих глаз, он меня бесит».
  3. Уточняющие вопросы (Параметры запроса).
    • Path parameters: «Борщ из свеклы» (/borshch/{svekla}).
    • Query parameters: «И дай мне две порции, с салом» (?count=2&with_salo=true).
    • Заголовки (Headers): Мета-инфо, типа «я — Вася Пупкин» (Authorization: Bearer VasyaToken) или «принеси в тарелке, а не в тазике» (Content-Type: application/json).
  4. Твоя записка официанту (Тело запроса). Ты пишешь на бумажке: «Хочу борщ. Свекла — обязательно. Чеснок — чем больше, тем лучше. Сметана — 50 грамм». Это и есть JSON, который ты передаёшь.
  5. Что тебе приносят в ответ (Тело ответа). Идеально: тарелка с борщом, ложка, салфетка. Неидеально: пустая тарелка и счёт втрое больше.
  6. Реакция официанта (Коды состояния HTTP). 200 — «держи, друг, горячий борщ». 404 — «братан, борщ закончился». 400 — «ты че, мудила, заказал борщ с ананасами?». 500 — «на кухне, блядь, повар упал в котёл».
  7. Чертёж блюда (Схемы данных). Это когда в меню не просто «борщ», а подробная схема: вес, температура, список ингредиентов с точностью до грамма. Чтобы нельзя было подсунуть свеклу прошлогоднюю.
  8. Пропуск в ресторан (Аутентификация). Без смокинга или без нашего токена — хуй ты зайдёшь в VIP-зал.
  9. Лимит на обжорство (Скоростные ограничения). Больше 10 тарелок борща в час — и тебя, обжору, вышвыривают на мороз.

Вот, смотри, как это выглядит в ихних офигительных бумажках (OpenAPI):

openapi: 3.0.0
paths:
  /users:
    post:
      summary: Создать нового юзера
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - name
              properties:
                email:
                  type: string
                  format: email # Это чтоб не написали "хуй@пизда.ру"
                name:
                  type: string
                  minLength: 2 # А то придет какой-нибудь "Й" и всё сломает
      responses:
        '201': # Всё заебись, пользователь создан
          description: User created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400': # А вот тут клиент накосячил, криворукий
          description: Invalid input data

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
          example: 42 # Вот, смотри, идеальный пример — ID 42, как ответ на главный вопрос

И вот зачем это всё QA, а не просто почитать и забыть:
С этим контрактом можно делать овердохуища крутых штук. Можно взять инструмент вроде Dredd и сказать: «Слушай, программа, вот контракт. Иди и долбись во все эндпоинты, проверь, чтобы сервер не херню какую-то возвращал, а то, что в документации». Автомат будет слать запросы, сверять ответы со схемой и орать, если что-то не так. Это называется тестирование на совместимость. Главная фишка в том, что если бэкендеры что-то поменяют на сервере, но контракт останется старым — твои тесты это сразу выловят, пока клиенты не начали звонить с воплями «всё сломалось, ёб твою мать!». По сути, ты страхуешь проект от внезапного пиздеца. Доверия к бэкенду — ебать ноль, поэтому и нужен такой железобетонный контракт.