sapl icon indicating copy to clipboard operation
sapl copied to clipboard

Impl expansão dinâmica de campos na API

Open LeandroJatai opened this issue 3 months ago • 0 comments

Mixin de Serializer que implementa expansão dinâmica de campos via parâmetros de query string:

  • expand: expande os campos informados
  • include: inclui apenas os campos informados
  • exclude: exclui os campos informados

Exemplos:

  • ?expand=campo1;campo2.sub_campo1,sub_campo2;campo3.sub_campo1.sub_sub_campo1,sub_sub_campo2
  • ?include=campo1;campo2.sub_campo1,sub_campo2;campo3.sub_campo1.sub_sub_campo1,sub_sub_campo2
  • ?exclude=campo1;campo2.sub_campo1,sub_campo2;campo3.sub_campo1.sub_sub_campo1,sub_sub_campo2
  • ?expand=campo1&include=campo1.id,name&exclude=campo1.secret_field

Onde:

  • campo1, campo2, campo3 são campos do model raiz
  • sub_campo1, sub_campo2 são campos relacionados do campo2
  • sub_sub_campo1, sub_sub_campo2 são campos relacionados do sub_campo1

Ou seja:

  • ";" separa campos independentes
  • "," separa campos relacionados do mesmo campo pai
  • "." indica aprofundamento do campo

e ainda:

  • expand pode ser usado para expansão direta, ou seja, campo1.sub_campo1 já expande campo1
  • expand, include e exclude podem ser usados juntos na mesma requisição
  • include e exclude só funcionam em subniveis se o campo pai estiver expandido
  • include tem precedência sobre exclude e já remove todo o resto
  • exclude remove o campo do resultado final, mesmo que esteja em include
  • Se nenhum dos parâmetros for informado, nenhum campo será expandido
  • Filtros da API, paginação (page e page_size) e ordenação (o) podem ser usados normalmente para filtrar os resultados

Atenção:

  • A expansão não é aplicada para o model User do Django
  • A expansão não é aplicada para campos customizados que utilizam SerializerMethodField
  • Uma exceção é lançada e registrada no log caso ocorra algum erro na expansão de algum campo, inclusive devido a recursão infinita
  • A expansão automática de todos os campos relacionados (expand=all) está desabilitada por necessidade de controle mais refinado.
  • A expansão de campos relacionados ForeignKey e OneToOne é suportada.
  • A expansão de campos relacionados ManyToMany é suportada.
  • A expansão de campos relacionados reversos (related_name) não é suportada, mas pode ser implementada manualmente no serializer customizado, ou vir a ser implementada no futuro.
  • O mixin ApiFilterSetMixin não aplica filtros nas expansões
  • selection_related e prefetch_related não são aplicados automaticamente, podendo ser implementados manualmente na viewset customizada, ou vir a ser implementados no futuro (pretendo fazer esta impl o mais rápido possível). Observo que, mesmo sem a aplicação destes recursos, a expansão é mais eficiente que sem ela, pois, invariavelmente, se o client precisar desses dados, atualmente ele o fará em uma nova requisição que fará o select da mesma forma.

Exemplos reais em produção já sendo utilizados no fork cmjatai/cmj:

Exemplo de expansão única: https://www.jatai.go.leg.br/api/materia/tramitacao/?expand=status image

Expandindo dois campos em mesmo nível: https://www.jatai.go.leg.br/api/materia/tramitacao/?expand=status;unidade_tramitacao_local image

Expansão em níveis diferentes: https://www.jatai.go.leg.br/api/materia/tramitacao/?expand=status;unidade_tramitacao_local.orgao image

Expansão com inclusão em conjunto em terceiro nível: https://www.jatai.go.leg.br/api/materia/tramitacao/?expand=status;unidade_tramitacao_local.orgao&include=unidade_tramitacao_local.orgao.id,nome,sigla image

Expansão, exclusão e inclusão em níveis diferentes: https://www.jatai.go.leg.br/api/materia/tramitacao/?expand=status;unidade_tramitacao_local.orgao&include=unidade_tramitacao_local.orgao.id,nome,sigla&exclude=unidade_tramitacao_local.link_detail_backend,comissao,parlamentar

Leitura completa deste link de exemplo:

  • expand faz com que status, unidade_tramitacao_local e unidade_tramitacao_local.orgao sejam expandidos
  • include informando que em orgao que ta dentro de unidade_tramitacao_local, seja recuperado apenas os campos id, nome e sigla de órgão.
  • exclude informando que em unidade_tramitacao_local os campos link_detail_backend, comissão, e parlamentar devem ser retirados da serialização image

os exemplos acima foram feitos só no endpoint /api/materia/tramitacao mas a dinamica já funciona na api inteira

LeandroJatai avatar Oct 29 '25 13:10 LeandroJatai