Skip to content

HTTP API OneFlag

OneFlag публикуется как приложение, а не как библиотека: экспортируемых классов у пакета нет, публичный контракт - это HTTP-эндпоинты. Здесь их полный список.

Разделы

Аутентификация

Защищённые эндпоинты принимают два вида доступа:

СпособЗаголовок или кукаКому
Ключ SDKAuthorization: Bearer <ONEFLAG_SDK_KEY>Приложениям и скриптам
Токен входаhttpOnly-кука, выдаётся POST /loginДашборду

Проверяются оба, порядок для итога не важен. Без валидного доступа возвращается 401 с телом application/problem+json.

Формат ошибок

Все ошибки API отдаются по RFC 9457:

Content-Type: application/problem+json
json
{ "type": "about:blank", "title": "Not Found", "status": 404, "detail": "Окружение qa не найдено" }
КодКогда
400Тело не является объектом JSON либо не заполнено обязательное поле
401Нет валидного ключа SDK и нет токена входа
404Флаг или окружение не найдены
405Метод не поддерживается точкой маршрута

Выбор окружения

Окружение берётся в следующем порядке:

  1. параметр строки запроса env;
  2. поле environment в теле запроса (там, где тело есть);
  3. ONEFLAG_DEFAULT_ENVIRONMENT.

Несуществующее окружение - 404.

Сводка

Метод и путьРаздел
GET /api/flags?env=devУправление
POST /api/flagsУправление
GET /api/flags/{ключ}Управление
PATCH, PUT /api/flags/{ключ}?env=devУправление
DELETE /api/flags/{ключ}Управление
GET /api/environmentsУправление
GET /api/audit?limit=50Управление
POST /api/evaluateОценка
POST /api/evaluate/allОценка
GET /api/snapshot?env=devОценка
GET /streamОценка
GET /healthzСлужебные
GET /metricsСлужебные
GET /stream/infoСлужебные

Маршруты дашборда (/, /login, /logout, /ui/...) отвечают фрагментами HTML для htmx и частью публичного контракта не считаются.


Оценка флагов

Контроллер app/КонтролОценки.os, префикс /api, и поток изменений /stream. Все эндпоинты требуют аутентификации; поток отдаётся без неё.

Оценивать флаги по HTTP нужно не всегда: oneflag-sdk забирает снимок один раз и дальше считает значения локально. Эти эндпоинты полезны для клиентов на других языках и для отладки.

Оценить флаг

POST /api/evaluate

Тело

ПолеТипНазначение
flagKeystringКлюч флага, обязательно
environmentstringОкружение; можно задать и параметром env
contextobjectАтрибуты пользователя, включая targetingKey
defaultValueлюбойЗначение при внештатной ситуации

Ответ 200

json
{"flagKey":"new-checkout","value":true,"variant":"вкл","reason":"TARGETING_MATCH","errorCode":""}
ПолеСодержимое
valueЗначение варианта либо defaultValue
variantИмя выбранного варианта, пустая строка при отказе
reasonSTATIC, TARGETING_MATCH, SPLIT, DISABLED или ERROR
errorCodeКод ошибки OpenFeature, пустая строка при успехе

Отсутствие флага - не ошибка HTTP: ответ 200 с errorCode = FLAG_NOT_FOUND и значением по умолчанию. Флаги не должны ронять вызывающего.

Пустой flagKey или тело не-объект - 400. Несуществующее окружение - 404.

bash
curl -X POST http://localhost:3333/api/evaluate \
  -H "Authorization: Bearer local-sdk-key" \
  -H "Content-Type: application/json" \
  -d '{"flagKey":"new-checkout","environment":"prod","context":{"targetingKey":"user-42","plan":"pro"}}'

Оценить все флаги

POST /api/evaluate/all

Тело

ПолеТипНазначение
environmentstringОкружение; можно задать и параметром env
contextobjectАтрибуты пользователя

Тело можно не передавать: тогда берётся окружение по умолчанию, а контекст считается пустым.

Ответ 200

json
{
  "environment": "prod",
  "flags": {
    "new-checkout": { "value": true, "variant": "вкл", "reason": "TARGETING_MATCH" },
    "dark-theme":   { "value": false, "variant": "выкл", "reason": "DISABLED" }
  }
}

Снимок конфигурации

GET /api/snapshot?env=dev

Отдаёт настройки всех флагов окружения без оценки: варианты, правила, процент выкатки. Это то, что забирает SDK при инициализации, чтобы дальше считать значения локально.

Ответ 200

json
{
  "environment": "dev",
  "flags": {
    "new-checkout": {
      "включен": true,
      "варианты": { "вкл": true, "выкл": false },
      "вариантПоУмолчанию": "вкл",
      "процентВыкатки": 25,
      "правила": [
        { "атрибут": "plan", "оператор": "равно", "значения": ["pro"], "вариант": "вкл" }
      ]
    }
  }
}

Поток изменений

GET /stream

Поток Server-Sent Events: text/event-stream, соединение держится открытым. Один и тот же поток слушают дашборды и SDK.

Событие приходит в формате CloudEvents 1.0, тип - один из com.oneflag.flag.created, com.oneflag.flag.changed, com.oneflag.flag.deleted.

event: com.oneflag.flag.changed
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
data: {"specversion":"1.0","type":"com.oneflag.flag.changed","source":"/oneflag", ...}

Соединение и keep-alive держит winow. При обрыве клиент переподключается с заголовком Last-Event-ID, поэтому пропущенные события догоняются.

Число открытых подписок видно в GET /stream/info и в метрике oneflag_stream_subscribers.

Ограничение. Поток работает только для клиентов того экземпляра сервиса, который принял изменение. Для нескольких экземпляров общее состояние держит postgresql, но событие в другой экземпляр не уходит.


Служебные эндпоинты

Аутентификации не требуют: их вызывают оркестратор и система мониторинга.

/healthz

GET /healthz

Контроллер app/КонтролСлужебный.os. Показатели считаются обращением к хранилищу, поэтому эндпоинт заодно проверяет, что база жива.

Ответ 200

json
{"status":"ok","flags":12,"environments":3,"subscribers":4}

Ответ 503

json
{"status":"error","error":"Не удалось открыть базу данных"}

Используется как healthcheck контейнера через healthcheck.os.

/metrics

GET /metrics

Метрики в формате Prometheus. Эндпоинт не написан в проекте: он встроен из пакета prometheus-metrics командой prometheus-metrics embed ./app, а сервис только регистрирует свои метрики в реестре prometheus.

МетрикаТипСмысл
oneflag_flagsgaugeФлагов в хранилище
oneflag_environmentsgaugeОкружений
oneflag_stream_subscribersgaugeОткрытых подписок на поток изменений
oneflag_audit_recordsgaugeЗаписей в журнале аудита
oneflag_flag_changes_totalcounterИзменения флагов, лейблы environment и event
oneflag_flag_evaluations_totalcounterОценки флагов, лейблы environment и reason

Показатели состояния считаются в момент сбора, а не хранятся копией: расхождение с хранилищем было бы незаметным и вводило бы в заблуждение. Недоступное хранилище даёт -1 - значение, отличимое от честного нуля.

Счётчик оценок разложен по причинам решения, поэтому по нему видно, чем вызвано значение флага: правилом таргетинга, процентной выкаткой или откатом к умолчанию.

/stream/info

GET /stream/info

Диагностика подписок на поток изменений.

Ответ 200

json
{"topic":"/stream","subscribers":4}

Управление флагами

Контроллер app/КонтролАПИ.os, префикс /api. Все эндпоинты требуют аутентификации.

winow маршрутизирует только по пути, поэтому метод запроса проверяется в контроллере вручную: неподдержанный метод даёт 405.

Список флагов

GET /api/flags?env=dev

Отдаёт все флаги вместе с их настройкой в указанном окружении.

Ответ 200

json
{
  "окружение": "dev",
  "флаги": [
    {
      "ключ": "new-checkout",
      "имя": "Новая корзина",
      "описание": "",
      "тип": "boolean",
      "варианты": { "вкл": true, "выкл": false },
      "настройка": {
        "включен": true,
        "вариантПоУмолчанию": "вкл",
        "процентВыкатки": 25,
        "правила": []
      }
    }
  ]
}

Поле настройка может быть null, если у флага нет записи для этого окружения.

Создать флаг

POST /api/flags

Тело

ПолеТипНазначение
ключstringИдентификатор флага
имяstringОтображаемое имя
описаниеstringНеобязательное пояснение
типstringboolean, string, number или object
вариантыobjectИмя варианта → значение

Ответ 201 - созданный флаг целиком.

Публикуется событие com.oneflag.flag.created.

bash
curl -X POST http://localhost:3333/api/flags \
  -H "Authorization: Bearer local-sdk-key" \
  -H "Content-Type: application/json" \
  -d '{"ключ":"new-checkout","имя":"Новая корзина","тип":"boolean"}'

Один флаг

GET /api/flags/{ключ}

Ответ 200 - описание флага со всеми окружениями. Несуществующий ключ - 404.

Изменить настройку

PATCH /api/flags/{ключ}?env=dev
PUT   /api/flags/{ключ}?env=dev

Меняет настройку флага в одном окружении. Оба метода делают одно и то же.

Тело

ПолеТипНазначение
включенbooleanФлаг включён в окружении
вариантПоУмолчаниюstringВариант, когда правила не сработали
процентВыкаткиnumberДоля аудитории, 0..100
правилаarrayПравила таргетинга

Ответ 200 - обновлённая настройка.

Публикуется событие com.oneflag.flag.changed с полями включен, вариантПоУмолчанию и процентВыкатки - именно на него реагируют SDK и открытые дашборды.

bash
curl -X PATCH "http://localhost:3333/api/flags/new-checkout?env=prod" \
  -H "Authorization: Bearer local-sdk-key" \
  -H "Content-Type: application/json" \
  -d '{"включен":true,"процентВыкатки":25}'

Удалить флаг

DELETE /api/flags/{ключ}

Ответ 204 без тела. Несуществующий ключ - 404.

Публикуется событие com.oneflag.flag.deleted.

Окружения

GET /api/environments

Ответ 200 - массив окружений с ключом, именем и порядком отображения. Состав задаётся переменной ONEFLAG_ENVIRONMENTS.

Аудит

GET /api/audit?limit=50

Журнал изменений, свежие записи первыми. По умолчанию limit равен 50; сколько записей хранится вообще, задаёт ONEFLAG_AUDIT_LIMIT.

Ответ 200 - массив записей. Каждая содержит событие CloudEvents 1.0 целиком плюс колонки для отбора.

Тип событияКогда
com.oneflag.flag.createdФлаг создан
com.oneflag.flag.changedНастройка флага в окружении изменена
com.oneflag.flag.deletedФлаг удалён