GH GambleHub

API linting и статический анализ

1) Зачем линтить API

API — контракт между командами и внешними интеграторами. Линтинг и статический анализ:
  • предотвращают несовместимые и неявные изменения;
  • унифицируют статусы, ошибки, пагинацию, безопасность;
  • делают спецификации машино-проверяемыми и релизы предсказуемыми;
  • сокращают стоимость ревью и время онбординга.

Принцип: «контракты проверяются автоматически; PR без зеленого линтинга не мержится».


2) Объекты линтинга

1. Контракты: OpenAPI/AsyncAPI/GraphQL SDL, Protobuf/Avro/JSON Schema.
2. Реализация: REST/gRPC-ручки, middleware, коды статусов/заголовки.
3. Инфраструктура: заголовки безопасности, лимиты, политики кэша.
4. Сопутствующие артефакты: примеры (examples), Postman-коллекции, схемы ошибок.


3) Базовые правила для HTTP API (рекомендуемый профиль)

3.1 Нотация и URL

snake_case в телах JSON, kebab-case в путях или единообразный kebab-case/`/v1/...`.
Ресурсы — множественное число: `/v1/payments`, вложенные — `/v1/wallets/{id}/transactions`.
Идентификаторы как path-params: `/v1/payments/{payment_id}` (тип: string, формат: uuid).

3.2 Методы и статусы

`GET` — 200/206; `POST` — 201 (+ `Location`), конфликты — 409; валидация — 422; лимиты — 429(+ `Retry-After`).
Не возвращать 200 для ошибок. Условные запросы — 304 по `If-None-Match`.

3.3 Ошибки (единый формат)

json
{ "code":"validation_error", "message":"amount must be ≥ 1", "trace_id":"...", "details":[{"field":"amount","reason":"min:1"}] }

Обязательны: `code`, `message`, `trace_id`; локаль — через `Content-Language`.

3.4 Пагинация/фильтры

Cursor-based: `page_size`, `page_token`, ответ: `next_page_token`.
Фильтры и сортировка — whitelists, документированные в `parameters`.

3.5 Безопасность

Единобразный security-схема: OAuth2/OIDC scopes или mTLS; запрещать `http` (только `https`).
Не возвращать чувствительные заголовки, маскировать токены в примерах.

3.6 Ограничения и размеры

Лимиты заголовков/тела: 413/414/431; документируйте максимально допустимые значения.


4) Инструменты и экосистема

4.1 OpenAPI

Spectral (JSON/YAML linт), Redocly linter, oas-diff/openapi-diff (semantic diff), schemathesis/dredd (выполняемые проверки).

4.2 Protobuf/gRPC

buf (lint + breaking check), protolint, генераторы SDK; gnostic для анализа.

4.3 GraphQL

graphql-schema-linter, graphql-inspector (breaking).

4.4 Кодовые линтеры и SAST

ESLint, golangci-lint, Detekt/Ktlint, Pylint/Flake8, Semgrep (шаблоны API-запахов и security).


5) Примеры правил: Spectral/Redocly

5.1 Spectral (пример `spectral.yaml`)

yaml extends: ["spectral:oas", "spectral:asyncapi"]
rules:
openapi-tags: off info-contact: error no-http: error path-kebab-case:
description: "Paths must be kebab-case"
given: "$.paths[]~"
severity: error then:
function: pattern functionOptions: { match: "^/(?:[a-z0-9]+(?--[a-z0-9]+)/?)+$" }
response-error-schema:
description: "Error responses must use standard schema"
given: "$.paths[][].responses[?(@property >= '400')]"
then:
field: "content.application/json.schema.$ref"
function: truthy id-as-uuid:
given: "$..parameters[?(@.name =~ /.id$/i)]"
then:
field: schema.format function: enumeration functionOptions: { values: ["uuid"] }

5.2 Redocly (фрагмент `.redocly.yaml`)

yaml apis:
main: openapi.yaml lint:
extends:
- recommended rules:
no-ambiguous-paths: error operation-2xx-only: off operation-success-response:
severity: error where:
subject: response filterInParentKeys: ["200","201","204"]
operation-security-defined: error no-plain-http: error

6) Protobuf/gRPC: buf-профиль

6.1 `buf.yaml`

yaml version: v2 modules:
- path: proto lint:
use:
- DEFAULT except:
- PACKAGE_VERSION_SUFFIX # используем v1 в package breaking:
use:
- WIRE_JSON deps: []
Рекомендации:
  • Не переиспользовать номера полей; удаляемые — в `reserved`.
  • Новые поля — `optional` или с дефолтами; не менять типы/семантику.

7) Семантический diff и «ломающие» изменения

7.1 HTTP

Breaking-примеры:
  • изменение типа/обязательности поля;
  • удаление статуса/маршрута/параметра;
  • сужение enum/диапазона;
  • смена формата id (uuid → string).
Небрейкинг:
  • добавление необязательных полей;
  • новые статусы, не влиящие на happy-path (например, документированный `422`);
  • расширение enum.

7.2 gRPC/Protobuf

Удаление поля без `reserved`/смена номера — breaking.
Изменение типа (int32 → string) — breaking.
Добавление нового тега как optional — обычно safe.


8) Связь линтинга контрактов и кода

Согласованность обеспечивается двумя потоками:

1. Контракт → код: генерация SDK/серверных заглушек, негативные примеры в тестах.

2. Код → контракт: спецификационные тесты, автоматическая проверка статусов/заголовков.

Semgrep-идеи:
  • запрет `return 200` при `error!= nil`;
  • обязательный `Idempotency-Key` на write-маршрутах платежей;
  • маскирование токенов в логах.

9) CI/CD пайплайн (референс)


pre-commit: spectral lint, redocly lint
PR gate:  openapi-diff (base..PR), buf breaking-check, graphql-inspector build:   schemathesis smoke, unit/integration linters (ESLint/golangci-lint)
release:  publish contracts (artifact/broker), sign & tag
PR должен падать, если:
  • есть breaking-diff;
  • нарушены базовые правила (статусы/безопасность/ошибки);
  • отсутствуют примеры/описания параметров.

10) Каталог правил (шаблон для вашей организации)

Идентификаторы и типы

`_id` — `string`, `format: uuid`.
Денежные поля — `string`/`decimal` с scale; валюта — ISO-4217.

Ошибки

Единая схема (см. §3.3), коды: `400/401/403/404/409/422/429/5xx`.
Всегда `trace_id`; `Retry-After` для 429/503.

Пагинация

Только cursor; max `page_size` документирован.

Безопасность

Все операции — `security` блок; описаны `scopes`.
Нет `http:` ссылок; TLS 1.2+.

Кэш/идемпотентность

Для GET — `ETag/Last-Modified`; для write — `Idempotency-Key` (где применимо).

Документация

`summary`, `description`, примеры запросов/ответов (валидные).


11) Примеры автоматизированных проверок

11.1 Проверка обязательных заголовков безопасности (Spectral)

yaml security-headers:
given: "$.paths[][].responses['200'].headers"
then:
function: truthy

11.2 openapi-diff (псевдо CI-шаг)


openapi-diff --fail-on-incompatible base.yaml pr.yaml

11.3 buf breaking-check


buf breaking --against '.git#branch=main'

12) Наблюдаемость качества контрактов

Метрики: доля PR с ошибками линтинга, время фикса, количество breaking-попыток, «долги» по правилам.
Дашборды: прогресс миграции на унифицированную схему ошибок, покрытие примерами, стабильность версий.


13) Антипаттерны

«Док» живет отдельно от кода → рассинхронизация. Держите контракт рядом с сервисом и выпускайте версионированным артефактом.
Линтер только вручную. Нужен жесткий PR-gate.
Случайные примеры (non-deterministic) — флейки в проверках.
Отсутствие негативных примеров и кодов ошибок.
Переизобретение схемы ошибок для каждого сервиса.
Игнорирование Protobuf breaking-проверок (меняют теги «на глазок»).


14) Специфика iGaming/финансов

Денежные поля — фиксированный масштаб/округление; запрет float.
Обязательные заголовки `X-Tenant`, `X-Region` и трассировка `traceparent`.
Платежные write-ручки: проверка наличия `Idempotency-Key`, `Retry-After` и корректных 409/201 семантик.
Вебхуки PSP/KYC: HMAC/mTLS описаны в `securitySchemes`; anti-replay (`X-Timestamp`, окно).
Региональные ограничения и локализация ошибок (`Content-Language`).


15) Чек-лист prod-готовности

  • Spectral/Redocly профили оформлены и подключены в pre-commit и PR-gate.
  • Единая схема ошибок и статусы — зафиксированы и проверяются.
  • openapi-diff/GraphQL Inspector/buf — блокируют breaking-изменения.
  • Примеры запросов/ответов валидны; пагинация/фильтры документированы.
  • SecuritySchemes и scopes заполнены; http-ссылок нет.
  • Для Protobuf: `reserved` на удаленных тегах; новые поля — optional.
  • Semgrep/линтеры кода включены; маскирование секретов в логах.
  • CI публикует артефакты контрактов и отчеты линтинга.
  • Плейбук: как действовать при breaking-диффе (rollback, hotfix, уведомления интеграторам).

16) TL;DR

Внедрите автоматический линтинг контрактов (Spectral/Redocly, buf/GraphQL Inspector) и семантический diff, зафиксируйте единую схему ошибок/статусов/пагинации/безопасности, подключите PR-gate и публикацию контрактов как артефактов. Любой breaking-дифф — стоп-сигнал. Для денег/платежей — особые правила (идемпотентность, `Retry-After`, HMAC/mTLS).

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.