AddressForAll / WS

Core infrastructure for AdressForAll Web Services
1 stars 0 forks source link

API internal catch-all function #11

Open ppKrauss opened 4 years ago

ppKrauss commented 4 years ago

Existem duas estratégias para implementar a resolução de parâmetros GET por regular expression:

  1. enviando a string inteira para uma "função catch-all" que faz o dispatch.
    Uma eventual vantagem é o tratamento centralizado de erros; a desvantagem é uma pequena perda de performance.
  2. gerando automaticamente o script NGINX com cada uma das resoluções.
    As vantagens seriam performance e gradualidade (permite automação mais tardia).

A estratégia 1 foi utilizada no primeiro rascunho do projeto. A estratégia 2 parecia ser a melhor, todavia não foi encontrada solução compacta no NGINX para resolver os 3 casos distintos (CSV/JSON/HTM). Tendo isso em vista, voltamos à estratégia inicial.


Problemas:

  1. PostgREST v7 está sem suporte para CSV de JSON array;
  2. funções que retornam tabelas precisariam ser submetidas ao select to_jsonb(t) from f($1) t e depois agregadas como array jsonb. Ainda assim não tem como retornar CSV nas condições atuais.
  3. Problemas clássicos de função retornando setof record, surgem com jsonb_populate_record e jsonb_to_record. Não tem como retornar "tipo record" para o CSV pois não existe tipo genérico.
  4. O NGINX também tem os seus problemas, apesar de menores.
ppKrauss commented 4 years ago

Solução meio gambiarra: organizar catch-all functions por tipo de retorno: se o tipo é o mesmo, o PostgreSQL permite usar uma só função com CASE para as demais.

  1. criar no esquema API da base SQL as funções uri_dispatch_x() agrupadoras de saída.
  2. criar no script NGINX os locations agrupadores de sintaxe e parametrização.
  3. revisar o sufixo x das funções uri_dispatch_x() para que sua sintaxe possa ser resolvida no NGINX.
ppKrauss commented 4 years ago

Outra opção....

ppKrauss commented 4 years ago

Resolvido no NGINX:

    # API /v1{formatoSaida}/{modulo}/{funcao}/{parametros}

    location ~ /v1(?:\.json)?/([a-z_][a-z0-9_]*)/([a-z_][a-z0-9_]*)/(.+) {
      proxy_pass http://localhost:3103/rpc/uridisp_$1_$2?p_uri=$3&$args;
    }
    location ~ /v1\.csv/([a-z_][a-z0-9_]*)/([a-z_][a-z0-9_]*)/(.+) {
      proxy_set_header Accept 'text/csv';
      proxy_pass http://localhost:3103/rpc/uridisp_$1_$2?p_uri=$3&$args;
    }

E resolvido no Postgresql, mantendo

Exemplos do módulo Eclusa do Projeto DigitalPreservation:

ppKrauss commented 4 years ago

Fechando a arquitetura em conformidade com http://addressForAll.org/api e step01-iniApi.sql ... usar api.addressforall.org/v1.json/ como listagem de urls ou de endpoints, ver https://api.github.com/
equanto request json de api.addressforall.org retorna versoes e demais metodos.

Outro problema, o fetch() do Javascript nao permite CORS (? ver fetch-crossorigin), ou algo se passa com /rpc NGINX vs /_sql direto .... Aceitou http://api-test.addressforall.org/_sql/origin_agg1 mas nao aceitou http://api-test.addressforall.org/_sql . Passou a aceitar com mode:no-cors mas dai dando erro "Uncaught (in promise) SyntaxError: JSON.parse: unexpected end".

ppKrauss commented 4 years ago

Por hora temos 3 motivacoes para a funcoes de RPC com sintaxe de filtragem no NGINX:

  1. Falha conceitual do PostgREST, que nao permite fazer "row filtering" (WHERE) sobre elementos ausentes do SELECT
  2. Falha no parser do PostgREST conforme https://github.com/PostgREST/postgrest-docs/issues/359
  3. Demanda interna do projeto por condicoes complexas (WHERE complexo), viabilizando o recurso para o usuario final.
0e1 commented 1 year ago

Tentando agrupar assuntos correlatos, trouxe https://github.com/AddressForAll/specifications/discussions/9 e https://github.com/AddressForAll/WS/issues/32 de Novembro/2021 para cá:

Portuguese

É necessário regrar um pouco melhor a oferta de APIs de cada domínio... Sugere-se mais ou menos o seguinte:

  1. API implementada por um período de teste em modo teste, para comprovar que não tem "efeitos colaterais" no servidor, e que contempla ambos, a especificação técnica inicial e as necessidades reais de quem usa.

  2. Controle dos nomes de API através de versionamento e jurisdição. Por exemplo a API do batista seria versão 1 (v1) da Colômbia, então o nome seria algo como API.addressforall.org/v1/CO/search

  3. Controle interno dos nomes de função no PostgreSQ/PostgREST, dentro do SQL-schema API: o acesso GET e POST se faz no NGINX por algo como
    proxy_pass http://localhost:$porta/rpc/uridisp_$1_$2?p_uri=$3&$args onde $1 é o módulo funcional (ex. addressfind), $2 o nome da API (ex. search), $3 o parâmetro default contendo o "resto do path na URL" e em $args os demais parâmetros, quando houverem. A declaração de função será sempre seguindo o template CREATE FUNCTION api.uridisp_{module}_{name}(p_uri text, {args}) RETURNING jsonb .... IMMUTABLE.

Nesta issue discutiremos diretamente o draft da documentação e a sua implementação final.


Depois de avançar na discussão, https://github.com/AddressForAll/specifications/discussions/9

  1. Revisar o README.md para que passe a ser conteúdo de /docs
  2. Criar em /docs/address-endpoints.md o rascunho da especificação.
  3. Criar exemplos de caso aderentes à proposta para testar as especificações
  4. Fechar a primeira versão.