Skip to content

Contrato do lookup de papéis — GET /roles/lookup ​

Base URL /api/v1. Erros em application/problem+json. Mesmo desenho da hidratação do diretório de usuários: user-directory-contract §3.2.

1. Para que serve ​

Alimentar o campo de referência de papel (type: 'reference' do gryd.ui): o combobox que grava só o id e mostra o nome. No admin-mfe ele substitui as listas de papéis escritas à mão — papéis de cada empresa na aba Acesso do usuário, papel padrão e mapeamentos de grupo do SSO.

Não é a listagem de papéis. GET /roles e GET /admin/tenants/{tenantId}/roles continuam sendo as telas de administração: devolvem o RoleDto com as permissões de cada papel e aceitam ordenação configurável. Usá-las num combobox carrega a matriz de permissões a cada tecla; e, para mostrar o nome de papéis já gravados, obrigava a tela a paginar todos os papéis da empresa (ou a mostrar o id cru do que ficava fora da 1ª página).

listagem (/roles, /admin/tenants/{id}/roles)lookup (…/roles/lookup)
ItemRoleDto com permissões{ id, name, description }
Ordenaçãoconfigurávelpor nome, fixa
pageSize máximo10050
Nome já gravadopaginar tudo?ids= em uma chamada
Permissãoa mesma do trilhoa mesma do trilho (§4)

2. Rotas ​

TrilhoRotaTenant lidoPermissão
tenantGET /api/v1/roles/lookupo do tokenread:roles
adminGET /api/v1/admin/tenants/{tenantId}/roles/lookupo da rotaadmin:system

As duas rotas têm o mesmo contrato. Em nenhuma delas o cliente manda o tenant por query string.

3. Requisição ​

GET /api/v1/roles/lookup?search=gest&page=1&pageSize=20&includeSystemRoles=true
GET /api/v1/roles/lookup?ids=3f1c…,9a72…
ParâmetroDefaultRegras
searchausentecasa o nome do papel, em qualquer posição, sem distinguir maiúsculas nem acentos (gestao acha Gestão). Não casa a descrição. % e _ são texto, não curinga. Máx. 100 caracteres
page11-based. Ignorado com ids
pageSize20máximo 50; acima disso é 400. Ignorado com ids
includeSystemRolestruefalse esconde papéis de sistema da busca. Ignorado com ids (§3.2)
idsausentehidratação: resolve estes ids em vez de buscar. Repetido (ids=a&ids=b) ou separado por vírgula (ids=a,b), com o mesmo resultado; duplicados ignorados; vazio = ausente. Máximo 50 ids distintos; acima disso, ou com um id malformado, 400

Não existe sortBy, sortDirection nem includeDeleted: a ordem é por nome e papel excluído nunca aparece.

3.1 Busca (sem ids) ​

Papéis do tenant, ordenados por nome, paginados. O envelope é o PagedResult<T> de sempre, com hasNext:

jsonc
{
  "items": [
    { "id": "3f1c…", "name": "Admin", "description": "Administra a empresa" },
    { "id": "9a72…", "name": "Gestão Financeira", "description": null }
  ],
  "totalCount": 12, "pageNumber": 1, "pageSize": 20,
  "totalPages": 1, "hasNext": false, "hasPrevious": false,
  "scope": null
}

3.2 Hidratação (?ids=) ​

A busca responde "que papel eu posso escolher?". Quando a tela já tem o id (vínculo gravado, papel padrão do SSO, mapeamento de grupo), a pergunta é outra: "qual o nome deste id?".

GET /api/v1/roles/lookup?ids=3f1c…,9a72…,c0de…
jsonc
{
  "items": [
    { "id": "3f1c…", "name": "Admin", "description": "Administra a empresa" },
    { "id": "9a72…", "name": "Vendedor", "description": null }
  ],
  "totalCount": 2, "pageNumber": 1, "pageSize": 3,
  "totalPages": 1, "hasNext": false, "hasPrevious": false,
  "scope": null
}
  • Uma chamada para a tela inteira. Junte os ids de todos os componentes (o getMany do react-admin) e faça uma requisição; com mais de 50 ids distintos, quebre em lotes de 50.
  • Uma página só. Todo id encontrado volta na página 1; page e pageSize não se aplicam, e o pageSize da resposta é a quantidade de ids distintos pedidos. Sem COUNT e numa consulta só.
  • Papel de sistema vem sempre, mesmo com includeSystemRoles=false: um papel já gravado num vínculo precisa mostrar o nome, ainda que a busca não o ofereça.
  • Id ausente da resposta = "Registro indisponível". Papel de outro tenant, excluído ou inexistente simplesmente não vem: status 200, sem 404 e sem nada que diferencie um caso do outro.
  • ids + search = AND (a interseção). Nenhum dos dois é ignorado em silêncio.
  • Não existe isActive. Papel não tem esse estado: ou existe no tenant, ou não vem.
ts
// junta os ids da tela e hidrata em lotes de 50
const chunks = chunk([...new Set(ids)], 50);
const pages = await Promise.all(chunks.map(c =>
  api.get(`/admin/tenants/${tenantId}/roles/lookup`, { params: { ids: c.join(",") } })));
const byId = new Map(pages.flatMap(p => p.items).map(r => [r.id, r]));
// byId.get(id) === undefined ⇒ "Registro indisponível"

3.3 O item ​

CampoTipoObservação
iduuido valor que a tela grava
namestringnome do papel
descriptionstring | nulldescrição do papel; null quando não há (ou está em branco). O campo sempre vem

Sem permissões, sem isSystemRole, sem tenantId. O que o combobox precisa é nome e descrição; o resto é da tela de administração.

4. Permissão ​

Cada trilho usa a permissão da listagem do mesmo trilho. Nada novo para conceder:

RotaAbre com
GET /roles/lookupread:roles (no tenant do token)
GET /admin/tenants/{tenantId}/roles/lookupadmin:system

⚠️ Assimetria registrada, sem mudança nesta entrega. O admin de papéis (/admin/tenants/{tenantId}/roles e agora o /lookup) aceita só admin:system. Já o admin de tenants (GET /admin/tenants, GET /admin/tenants/{id}) aceita também manage:all-tenants, e o de usuários (/admin/users/*) aceita também manage:all-users. Resultado prático: um administrador global com escopo restrito (manage:all-users sem admin:system) edita os vínculos de um usuário, mas recebe 403 ao buscar ou hidratar os papéis da empresa. Se o admin-mfe for usado por esse perfil, a aba Acesso precisa tratar o 403 (ou o backend precisa abrir o admin de papéis a manage:all-*, o que é uma decisão à parte).

5. Erros ​

SituaçãoHTTPcode
sem token401—
sem a permissão do trilho (§4)403—
pageSize fora de 1–50, page < 1, search > 100400validação
mais de 50 ids distintos; ids com valor que não é um id400validação
tenantId da rota que não é um uuid404— (a rota não casa)

Ramifique sempre pelo code; title e detail são localizados (en, pt-BR, es-ES).

O endpoint não tem rate limit próprio (o do diretório existe porque a lista de pessoas é o alvo de enumeração). Mesmo assim, faça debounce de ~300 ms na busca e cancele a requisição anterior.

Released under the MIT License.