HTTP API OneFlag
OneFlag публикуется как приложение, а не как библиотека: экспортируемых классов у пакета нет, публичный контракт - это HTTP-эндпоинты. Здесь их полный список.
Разделы
- Управление флагами - создание, изменение и удаление флагов, окружения, аудит
- Оценка флагов - оценка, снимок конфигурации, поток изменений
- Служебные эндпоинты - здоровье, метрики, сведения о потоке
Аутентификация
Защищённые эндпоинты принимают два вида доступа:
| Способ | Заголовок или кука | Кому |
|---|---|---|
| Ключ SDK | Authorization: Bearer <ONEFLAG_SDK_KEY> | Приложениям и скриптам |
| Токен входа | httpOnly-кука, выдаётся POST /login | Дашборду |
Проверяются оба, порядок для итога не важен. Без валидного доступа возвращается 401 с телом application/problem+json.
Формат ошибок
Все ошибки API отдаются по RFC 9457:
Content-Type: application/problem+json{ "type": "about:blank", "title": "Not Found", "status": 404, "detail": "Окружение qa не найдено" }| Код | Когда |
|---|---|
400 | Тело не является объектом JSON либо не заполнено обязательное поле |
401 | Нет валидного ключа SDK и нет токена входа |
404 | Флаг или окружение не найдены |
405 | Метод не поддерживается точкой маршрута |
Выбор окружения
Окружение берётся в следующем порядке:
- параметр строки запроса
env; - поле
environmentв теле запроса (там, где тело есть); 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Тело
| Поле | Тип | Назначение |
|---|---|---|
flagKey | string | Ключ флага, обязательно |
environment | string | Окружение; можно задать и параметром env |
context | object | Атрибуты пользователя, включая targetingKey |
defaultValue | любой | Значение при внештатной ситуации |
Ответ 200
{"flagKey":"new-checkout","value":true,"variant":"вкл","reason":"TARGETING_MATCH","errorCode":""}| Поле | Содержимое |
|---|---|
value | Значение варианта либо defaultValue |
variant | Имя выбранного варианта, пустая строка при отказе |
reason | STATIC, TARGETING_MATCH, SPLIT, DISABLED или ERROR |
errorCode | Код ошибки OpenFeature, пустая строка при успехе |
Отсутствие флага - не ошибка HTTP: ответ 200 с errorCode = FLAG_NOT_FOUND и значением по умолчанию. Флаги не должны ронять вызывающего.
Пустой flagKey или тело не-объект - 400. Несуществующее окружение - 404.
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Тело
| Поле | Тип | Назначение |
|---|---|---|
environment | string | Окружение; можно задать и параметром env |
context | object | Атрибуты пользователя |
Тело можно не передавать: тогда берётся окружение по умолчанию, а контекст считается пустым.
Ответ 200
{
"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
{
"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
{"status":"ok","flags":12,"environments":3,"subscribers":4}Ответ 503
{"status":"error","error":"Не удалось открыть базу данных"}Используется как healthcheck контейнера через healthcheck.os.
/metrics
GET /metricsМетрики в формате Prometheus. Эндпоинт не написан в проекте: он встроен из пакета prometheus-metrics командой prometheus-metrics embed ./app, а сервис только регистрирует свои метрики в реестре prometheus.
| Метрика | Тип | Смысл |
|---|---|---|
oneflag_flags | gauge | Флагов в хранилище |
oneflag_environments | gauge | Окружений |
oneflag_stream_subscribers | gauge | Открытых подписок на поток изменений |
oneflag_audit_records | gauge | Записей в журнале аудита |
oneflag_flag_changes_total | counter | Изменения флагов, лейблы environment и event |
oneflag_flag_evaluations_total | counter | Оценки флагов, лейблы environment и reason |
Показатели состояния считаются в момент сбора, а не хранятся копией: расхождение с хранилищем было бы незаметным и вводило бы в заблуждение. Недоступное хранилище даёт -1 - значение, отличимое от честного нуля.
Счётчик оценок разложен по причинам решения, поэтому по нему видно, чем вызвано значение флага: правилом таргетинга, процентной выкаткой или откатом к умолчанию.
/stream/info
GET /stream/infoДиагностика подписок на поток изменений.
Ответ 200
{"topic":"/stream","subscribers":4}Управление флагами
Контроллер app/КонтролАПИ.os, префикс /api. Все эндпоинты требуют аутентификации.
winow маршрутизирует только по пути, поэтому метод запроса проверяется в контроллере вручную: неподдержанный метод даёт 405.
Список флагов
GET /api/flags?env=devОтдаёт все флаги вместе с их настройкой в указанном окружении.
Ответ 200
{
"окружение": "dev",
"флаги": [
{
"ключ": "new-checkout",
"имя": "Новая корзина",
"описание": "",
"тип": "boolean",
"варианты": { "вкл": true, "выкл": false },
"настройка": {
"включен": true,
"вариантПоУмолчанию": "вкл",
"процентВыкатки": 25,
"правила": []
}
}
]
}Поле настройка может быть null, если у флага нет записи для этого окружения.
Создать флаг
POST /api/flagsТело
| Поле | Тип | Назначение |
|---|---|---|
ключ | string | Идентификатор флага |
имя | string | Отображаемое имя |
описание | string | Необязательное пояснение |
тип | string | boolean, string, number или object |
варианты | object | Имя варианта → значение |
Ответ 201 - созданный флаг целиком.
Публикуется событие com.oneflag.flag.created.
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 и открытые дашборды.
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 | Флаг удалён |
