O desenvolvimento de APIs permite a exposição e o consumo de dados com o objetivo da integração (front-end, portais, customizações, etc) ao back-end do produto Datasul, de maneira segura e padronizada.
A estrutura de integração de APIs Datasul suporta o envio de requisições no estilo de arquitetura REST com o desenvolvimento da regra de negócio em Progress.
Abaixo o fluxo das requisições via HTTP (DATASUL-REST) e formato de execução via Progress:

Esta funcionalidade está disponível para utilização conforme apresentado no quadro abaixo:
|
Esta funcionalidade está disponível para utilização conforme apresentado no quadro abaixo:
O Guia de Implementação de API TOTVS define que o formato das URIs dos endpoints devem conter o nome do produto, o módulo, a versão da API e o recurso alvo da
funcionalidade em questão.
Tomando como exemplo o endpoint de integração do recurso de "Usuários" do módulo de "Foundation" do produto "Datasul", a URI básica deste serviço deve ser: /prg/fnd/v1/users
Para o produto Datasul, o serviço responsável é implementado no contexto /dts/datasul-rest/, desta forma, a URL final do serviço exemplo acima seria composta da seguinte maneira:
http://host:port/dts/datasul-rest/resources/prg/fnd/v1/users |
A URL definida pelo Padrão de API TOTVS segue o seguinte formato: /dts/datasul-rest/resouces/prg/<módulo>/<versão API>/<recurso>/ Informações que forem passadas após o recurso, serão tratadas como parâmetros PATH. |
Para exemplo do funcionamento /api vamos utilizar o mesmo recurso de integração de usuário exemplificado anteriormente: a URI deste serviço deve ser: /api/fnd/v1/users
No geral o funcionamento do /api é igual ao /prg, com a ressalva de que o endpoint /api não esta dentro do contexto /dts/datasul-rest/
A URL definida pelo Padrão de API TOTVS segue o seguinte formato: /api/<módulo>/<versão API>/<recurso>/ Informações que forem passadas após o recurso, serão tratadas como parâmetros PATH. |
Para "publicar" a funcionalidade Progress ABL basta criar o programa (.p) com o seguinte caminho: fnd/api/v1/users.p (<módulo>/api/<versão API>/<recurso>.p). A sub-pasta "api" passa então a concentrar todas as funcionalidades de integração do módulo em questão. Outros caminhos e parâmetros podem ser adicionados a URL, mas sempre de acordo com o Guia de Implementação de APIs.
Os programas Progress disponibilizados, deverão seguir o padrão de localização abaixo: <módulo>/api/<versão API>/<recurso>.p |
O Guia de Implementação de API TOTVS define também que a troca de mensagens é feita (impreterivelmente) no formato JSON, e por conta disso, a troca de mensagens com as funcionalidades Progress também deve ser feita nesse formato, mais especificamente por meio de um parâmetro de entrada e outro de saída do tipo LONGCHAR que devem ser devidamente tratados (parseados e formatados) pela funcionalidade através das includes utilitárias disponibilizadas:
Abaixo um exemplo de recurso desenvolvido em Progress ABL para ser utilizado junto ao serviço de API:
{utp/ut-api.i}
{utp/ut-api-action.i pi-send GET /~*/SEND by=email,address=~* }
{utp/ut-api-action.i pi-update POST /~* }
{utp/ut-api-action.i pi-find GET /~* }
{utp/ut-api-action.i pi-default GET }
{utp/ut-api-notfound.i}
PROCEDURE pi-send:
DEF INPUT PARAM jsonInput AS JsonObject NO-UNDO.
DEF OUTPUT PARAM jsonOutput AS JsonObject NO-UNDO.
DEFINE VARIABLE aJsonArray AS JsonArray NO-UNDO.
DEFINE VARIABLE oJsonObject AS JsonObject NO-UNDO.
aJsonArray = NEW JSONArray().
oJsonObject = NEW JSONObject().
oJsonObject:ADD("teste", "teste").
oJsonObject:ADD("teste1", "teste1").
oJsonObject:ADD("teste2", "teste2").
aJsonArray:ADD(oJsonObject).
oJsonObject = NEW JSONObject().
oJsonObject:ADD("teste", "teste").
oJsonObject:ADD("teste1", "teste1").
oJsonObject:ADD("teste2", "teste2").
aJsonArray:ADD(oJsonObject).
jsonOutput = JsonAPIResponseBuilder:ok(aJsonArray, false).
END.
PROCEDURE pi-update:
DEF INPUT PARAM jsonInput AS JsonObject NO-UNDO.
DEF OUTPUT PARAM jsonOutput AS JsonObject NO-UNDO.
jsonOutput = NEW JSONObject().
jsonOutput = jsonInput.
END.
PROCEDURE pi-find:
DEF INPUT PARAM jsonInput AS JsonObject NO-UNDO.
DEF OUTPUT PARAM jsonOutput AS JsonObject NO-UNDO.
jsonOutput = NEW JSONObject().
jsonOutput:ADD("method", "GET").
jsonOutput:ADD("procedure", "pi-find").
jsonOutput:ADD("description", "Test").
END.
PROCEDURE pi-default:
DEF INPUT PARAM jsonInput AS JsonObject NO-UNDO.
DEF OUTPUT PARAM jsonOutput AS JsonObject NO-UNDO.
jsonOutput = NEW JSONObject().
jsonOutput:ADD("method", "GET").
jsonOutput:ADD("procedure", "pi-default").
jsonOutput:ADD("description", "Test").
END. |
No exemplo acima, temos as seguintes includes utilitárias:
{utp/ut-api.i}É a include principal, que possui os parâmetros de entrada e saída do serviço API, nesta include é feito a inicialização das funções utilitárias.
{utp/ut-api-action.i pi-send GET /~*/SEND by=email,address=~* }Neste exemplo, está sendo definido uma rota, sendo que toda requisição de método GET, que contenha os filtros informados, será direcionado a procedure pi-send.
/~*/SEND by=email,address=~*
Em relação ao filtro informado, será capturado todas as requisições que possuírem um parâmetro Path "SEND", um parâmetro Query "by" com conteúdo "email" e um parâmetro Query "address" com qualquer conteúdo (*).
{utp/ut-api-action.i pi-update POST /~* }No exemplo acima, está sendo definida uma rota, no qual toda requisição de método POST, será direcionada para a procedure pi-update.
{utp/ut-api-action.i pi-find GET /~* }Neste exemplo, todas as requisições de método GET, que possuirem parâmetros (Query ou Path) informados, será direcionado para a procedure pi-find.
{utp/ut-api-action.i pi-default GET }No exemplo acima, para requisições de método GET, que não encontrarem nenhuma rota compatível, será direcionada para a procedure pi-default.
{utp/ut-api-notfound.i}Caso nenhuma procedure interna tenha sido encontra retorna uma mensagem "Method not found" com HTTP Status 400.
Algumas considerações sobre o uso da include de roteamento (ut-api-action):
|
A include ut-api.i precisa ser adicionada obrigatoriamente no início do programa Progress, visto que esta include faz uso da instrução USING para importação de classes. Portanto, devido a esta caraterística do Progress ABL, somente será possível adicionar outras includes depois da adição da ut-api.i e ut-api-notfound.i, respectivamente. |
O objeto JsonObject, recebido pela requisição no programa Progress conterá informações completas da requisição, desde informações do HEADER, QUERY PARAMs, PATH PARAMs, o próprio PAYLOAD e arquivos MULTIPART. Através desta mensagem, o desenvolvedor poderá efetuar os devidos filtros e classes utilitárias necessárias.
Exemplo de mensagem:
{
uri: valor,
method: GET,
headers: {},
pathParams: [ "param1", "param2" ],
queryParams: { query1: [valor1, valor2], query2: [valor1]},
payload: { },
multyPartFile: [ {file: ...}, {file: ...}]
} |
Com o objetivo de facilitar a manipulação dos objetos JsonObject recebidos e enviados pela API Progress foram desenvolvidas algumas classes de utilitários:
Para realizar o login no DATASUL-REST é necessário passar como parâmetro usuário e senha na seguinte URL.
http://localhost:8180/dts/datasul-rest/resources/login?username=USER&password=PASSWORD |
Para passagem da senha é necessário converte-la para SHA1, com este resultado realizar a conversão para BASE64. Tendo em vista que a conversão para BASE64 irá trazer caracteres incoerentes para passagem da URL, será necessário fazer a conversão para URL-ENCODE.
Observe que por trazer os caracteres " / e = " na conversão de SHA1 e BASE64, é necessário o URL-ENCODE.
DEFINE VARIABLE testPass AS CHARACTER NO-UNDO.
testPass = BASE64-ENCODE(SHA1-DIGEST(LC("testPassword"))).
// Utilize uma lógica de conversão URL-ENCODE para variavel testPass |
http://localhost:8180/dts/datasul-rest/resources/login?username=super&password=i7YRj4%2FWk1rQh2o740pxfTJwj%2F0%3D |