GET /api/v1/handbook/{countries,regions,cities,currencies,languages} — Публичный lookup справочников
Назначение
Консолидированный документ пяти read-only lookup-операций над справочниками платформы: страны, регионы, города, валюты, языки. Отдаёт фронтам (включая гостя до регистрации) неархивные записи для подстановки в фильтры каталога, гео-поля форм и денежные/языковые селекторы.
Пять операций обслуживаются одной формой: различие — тип записи, фильтры и (только у городов) пагинация и поиск.
Наполнение справочников — синк Talent Handbook (ADR-0063); ведения данных через это API нет.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | handbook |
| API area | public |
| Feature group | lookup |
| Статус | draft |
| Документ | docs/06-services/handbook/api/public/lookup-references.md |
Актор и доступ
| Проверка | Значение |
|---|---|
| Actor type | Anonymous — авторизация не требуется (гость видит фильтры каталога до регистрации) |
| Auth policy / Permissions | none |
| Scope (RBAC) | не применяется — справочники платформенные, публичные |
| Tenant isolation | не применяется |
| Audit | не пишется (публичные не-PII данные); защита от злоупотреблений — кэшируемость ответов + платформенный rate limit анонимных запросов |
HTTP-контракт
| Поле | Значение |
|---|---|
| Method | GET (все 5) |
| Routes | /api/v1/handbook/countries · /api/v1/handbook/regions?countryId= · /api/v1/handbook/cities?countryId=®ionId=&search=&page=&pageSize= · /api/v1/handbook/currencies · /api/v1/handbook/languages |
| Success status | 200 (в т.ч. пустой список) |
| Кэширование | Cache-Control: public, max-age=300 на всех ответах — данные меняются редко, устаревание до 5 минут допустимо |
| Correlation | сквозной trace через заголовок traceparent |
Входные данные / параметры запроса
Страны, валюты, языки — без параметров (выдаются целиком: десятки строк).
Регионы:
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения |
|---|---|---|---|---|
countryId | query | short | Да | страна, регионы которой запрашиваются; несуществующий id → пустой список (не ошибка) |
Города (единственный постраничный справочник — тысячи строк):
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения |
|---|---|---|---|---|
countryId | query | short? | Нет | фильтр по стране; несуществующий id → пустой список |
regionId | query | long? | Нет | фильтр по региону; сочетается с countryId конъюнктивно |
search | query | string? | Нет | trim; если задан — 2..256 символов; подстрока имени, case-insensitive |
page | query | int | Нет (default 1) | >= 1 |
pageSize | query | int | Нет (default 50) | 1..200 |
Сортировка всех выдач — по Name (возр., case-insensitive), при равенстве — по Id; фиксирована на
сервере, клиент порядок не задаёт.
Модели ответа
Проекции реплик; дома полей — ../../domain/, здесь только выдаваемая дельта. Служебные
поля (IsArchived, ReplicaVersion/LastEventAt, штампы) наружу не выдаются — в выдаче только неархивные
записи (INV-HND-5). Непагинированные списки — контейнер { Items: [...] }; города — постраничный контейнер
{ Items, Page, PageSize, TotalCount }.
CountryLookupItem (/countries)
| Поле | Тип | Обязательность | Источник | Описание |
|---|---|---|---|---|
Id | short | Да | CountryEntity.Id | Идентификатор страны (подставляется в CountryId контрактов). |
Name | string | Да | CountryEntity.FullName | Display-имя (конвенция Name = FullName, country.md). |
ShortName | string? | Нет | .ShortName | Краткое название («Россия»). |
IsoCode2 | string | Да | .IsoCode2 | ISO 3166-1 alpha-2 (RU) — флаги, внешние интеграции. |
IsoCode3 | string | Да | .IsoCode3 | ISO 3166-1 alpha-3 (RUS). |
DefaultCurrencyId | short? | Нет | .DefaultCurrencyId | Валюта страны по умолчанию. |
DefaultLanguageId | short? | Нет | .DefaultLanguageId | Язык страны по умолчанию. |
RegionLookupItem (/regions)
| Поле | Тип | Обязательность | Источник | Описание |
|---|---|---|---|---|
Id | long | Да | RegionEntity.Id | Идентификатор региона. |
CountryId | short | Да | .CountryId | Страна региона (эхо фильтра). |
Name | string | Да | .Name | Название региона («Самарская область»). |
CityLookupItem (/cities)
| Поле | Тип | Обязательность | Источник | Описание |
|---|---|---|---|---|
Id | long | Да | CityEntity.Id | Идентификатор города. |
CountryId | short | Да | .CountryId | Страна города. |
RegionId | long? | Нет | .RegionId | Регион города; null — город вне региона (напр., федерального значения). |
Name | string | Да | .Name | Название города («Самара»). |
CurrencyLookupItem (/currencies)
| Поле | Тип | Обязательность | Источник | Описание |
|---|---|---|---|---|
Id | short | Да | CurrencyEntity.Id | Идентификатор валюты (подставляется в CurrencyId контрактов). |
Name | string | Да | .Name | Название («Российский рубль»). |
IsoCode | string | Да | .IsoCode | Код ISO-4217 (RUB). |
Sign | string? | Нет | .Sign | Знак валюты («₽»). |
LanguageLookupItem (/languages)
| Поле | Тип | Обязательность | Источник | Описание |
|---|---|---|---|---|
Id | short | Да | LanguageEntity.Id | Идентификатор языка. |
Name | string | Да | .Name | Название («Русский»). |
IsoCode2 | string | Да | .IsoCode2 | ISO 639-1 (ru). |
IsoCode3 | string | Да | .IsoCode3 | ISO 639-2/3 (rus). |
FlagIsoCode2 | string? | Нет | .FlagIsoCode2 | ISO-код страны для отрисовки флага языка. |
Алгоритм
Операции read-only, событий не публикуют, данных не меняют.
- Проверка входа. Регионы:
countryIdзадан — иначеVALIDATION_FAILED. Города:page >= 1,pageSize ∈ 1..200,search(если задан) после trim —2..256символов — иначеVALIDATION_FAILED. Остальные операции параметров не имеют. - Выборка. Только неархивные записи справочника (
IsArchived = false, INV-HND-5); фильтры — конъюнкция заданных параметров (countryId,regionId, подстрокаsearchcase-insensitive по имени). Несуществующее значение фильтра (нет такой страны/региона) — пустой результат, не ошибка. Сортировка — по имени. - Результат.
200+ контейнерItems(города — сPage/PageSize/TotalCount); заголовокCache-Control: public, max-age=300. Пустой список валиден. Архивная запись в выдачу не попадает — резолв архивных по id доступен только внутренним сервисам (resolve-references.md).
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|---|---|---|---|
VALIDATION_FAILED | 400 | регионы: countryId не задан или не является числом | «Проверьте параметры запроса» | no retry |
VALIDATION_FAILED | 400 | города: page < 1 либо pageSize вне 1..200 | «Проверьте параметры запроса» | no retry |
VALIDATION_FAILED | 400 | города: search задан и после trim короче 2 символов либо длиннее 256 | «Поисковая строка — от 2 до 256 символов» | no retry |
200 c Items = [] (у городов — TotalCount = 0). 404 в списочных операциях не используется.
Acceptance Criteria
- Страны. Given справочник стран с архивной записью; When
GET /api/v1/handbook/countries; Then200,Itemsсодержит только неархивные страны, отсортированные по имени, с полямиId/Name/ShortName/IsoCode2/IsoCode3/DefaultCurrencyId/DefaultLanguageId; архивной страны в выдаче нет. - Регионы по стране. Given страна
countryId = 1с регионами; WhenGET /regions?countryId=1; Then200и только неархивные регионы этой страны. - Регионы без страны. Given запрос без
countryId; WhenGET /regions; Then400 VALIDATION_FAILED. - Города: дефолтная страница. Given тысячи городов; When
GET /cities?countryId=1; Then200,Page = 1,PageSize = 50,TotalCount= числу неархивных городов страны. - Города: поиск подстрокой. Given город «Самара»; When
GET /cities?search=мар; Then200, «Самара» в выдаче (case-insensitive подстрока). - Города: короткий поиск. Given
search=с(1 символ); When запрос; Then400 VALIDATION_FAILED. - Города: предел страницы. Given
pageSize=201; When запрос; Then400 VALIDATION_FAILED; GivenpageSize=200— Then200. - Несуществующий фильтр. Given
countryId=999отсутствует в справочнике; WhenGET /cities?countryId=999; Then200,Items = [],TotalCount = 0(не ошибка). - Кэшируемость. Given любой успешный ответ; Then заголовок
Cache-Control: public, max-age=300. - Анонимный доступ. Given запрос без токена авторизации; When любая из 5 операций; Then
200(авторизация не требуется).
Совместимость и наблюдаемость
Новые optional-поля lookup-моделей — additive без breaking; удаление/переименование/смена типа поля или маршрута — breaking (согласованный rollout с фронтами). Состав выдачи стабилен: только неархивные записи — инвариант контракта (INV-HND-5), а не деталь реализации.
- Клиент обязан переживать рост числа записей (новые страны/валюты источника появляются без изменения контракта).
- Logs:
handbook-lookup requested(kind =country|region|city|currency|language, наличие фильтров,resultCount) — без параметров поиска в открытом виде не требуется, PII нет; metrics:handbook_lookup_total{kind}, latency p95; traces — OTel (traceparent); dashboardhandbook-overview. Runbook не требуется: read-only, деградация = устаревшая (≤ max-age) или пустая выдача.
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (3): Entity / Aggregate: ActionEvent (TPH-иерархия событий действий), Entity: CityEntity, Entity: CountryEntity
- API (6): GET /api/agent/crm/leads/{leadId} — Карточка лида, GET /api/v1/agency/commission-policies — Список комиссионных политик агентства, Handbook API — реестр операций областей public / internal / admin, Investor-Owner API — реестр операций и общие контрактные модели, POST /internal/handbook/resolve — Batch-резолв справочных записей по id, Rewards API — реестр операций и общие контрактные модели
- Use Cases (2): UC-HND-001. Администратор поддерживает справочник (archive/restore), US-реестр контекста handbook (US-HND)
- index.md (1): Handbook Service
- registries (1): Реестр API-методов PIN
Связанные документы
- Дома полей: country.md, region.md, city.md, currency.md, language.md; INV-HND-5 — country.md.
- Резолв по id (включая архивные, m2m): resolve-references.md.
- Архив/восстановление записей (admin): archive-restore-entry.md.
- Реестр операций и правила областей: ../README.md; ADR-0063 п.7 (lookup — PostgreSQL).