Árvore de páginas

Introdução


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:

Matriz de Evolução



Contextos


Existem 2 contextos definidos que se aplicam tanto para a Antiga arquitetura (Jboss) quanto para o DTS4THF (Tomcat).

Estes contextos tem o objetivo de definir o acesso das requisições, ou seja, se são contextos de acessos internos (via menu) pelo contexto DTS/DATASUL-REST ou acessos externos (via APPs por exemplo) pelo contexto /API.


IMPORTANTE!

O contexto /api foi criado com autenticação via "Basic Authentication", para atender o guia de API TOTVS, sendo possível conexão com qualquer API que anteriormente era "dts/datasul-rest/resources/prg".




Formato URL


O Guia de Implementação de API TOTVS define que no formato das URIs dos endpoints deve conter:

  • o nome do produto;
  • o módulo;
  • a versão da API;
  • o recurso alvo da funcionalidade em questão.

Modelo de acesso aos Contextos:


/prg


Tomando como exemplo o endpoint de integração do recurso de "Usuários" do aplicativo "Foundation" do produto "Datasul", a URI básica deste serviço deve ser: /prg/sec/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/sec/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.


/api


Para exemplo do funcionamento /api vamos utilizar o mesmo recurso de integração de usuário exemplificado anteriormente.

URI deste serviço deve ser: /api/sec/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/


http://host:port/api/sec/v1/users


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.




Serviço Progress


Para "publicar" a funcionalidade Progress ABL basta criar o programa (.p) com o seguinte caminho: sec/api/v1/users.p (<módulo>/api/<versão API>/<recurso>.p). 

O arquivo *.p é  o fonte original de criação da API, porém para sua real utilização é preciso compilá-lo para se transformar em um arquivo *.r.


A sub-pasta "api" passa então a concentrar todas as funcionalidades de integração do módulo em questão:

Os programas Progress disponibilizados, deverão seguir o padrão de localização abaixo e devem estar compilados, ou seja, é necessário o *.r:

<módulo>/api/<versão API>/<recurso>.r


OBS: Outros caminhos e parâmetros podem ser adicionados a URL, mas sempre de acordo com o Guia de Implementação de APIs.


     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 devem ser feitas 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 utilizando as includes utilitárias disponibilizadas:

IncludeParâmetros da IncludeDescrição

utp/ut-api.i

Não há.Faz o parser do parâmetro LONGCHAR de entrada e cria um objeto JsonObject chamado jsonInput.
utp/ut-api-action.i
  1. Nome da procedure interna que deve ser executada.
  2. Método da Requisição.
  3. Rota.
Faz o roteamento do objeto jsonInput para uma procedure interna especificada pelo desenvolvedor.

utp/ut-api-notfound.i

Não há.Caso nenhuma procedure interna tenha sido encontrada, retorna uma mensagem "Method not found" com HTTP Status 400.


Para garantir o controle de erros, controle de chamada EPC e padronização no retorno das mensagens, foram criadas includes para executar os principais Endpoints, além de permitir a chamada de Endpoints específicos de negócio:

IncludeParâmetros da IncludeEndpointDescriçãoParâmetros enviado para PI Interna

utp/ut-api-exec-metadata.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
MetadataDevolve metadata para geração das telas.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. cEvent (INPUT): Evento solicitado pelo Front (list, new, edit, copy ou detail);
  3. cVersion (INPUT): Versão solicitada pelo Front;
  4. oOutput (OUTPUT): Objeto de Metatadata;
  5. RowErrors (OUTPUT): TempTable de Erros.

utp/ut-api-exec-vld-form.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
VldFormValidação de formulário.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
  3. RowErrors (OUTPUT): TempTable de Erros.

utp/ut-api-exec-vld-field.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
VldFieldValidação de campo.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
  3. RowErrors (OUTPUT): TempTable de Erros.

utp/ut-api-exec-get.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
GetBusca um registro.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
  3. cExpandables (OUTPUT): Lista de entidades "filhas" separadas por vírgula;
  4. RowErrors (OUTPUT): Tempable de Erros.

utp/ut-api-exec-query.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
QueryBusca vários registros.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. aResult (OUTPUT): Array retornado pelo programa de negócio;
  3. lHasNext (OUTPUT): Indicação se existem mais registros;
  4. cExpandables (OUTPUT): Lista de entidades "filhas" separadas por vírgula;
  5. RowErrors (OUTPUT): TempTable de Erros.

utp/ut-api-exec-create.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
CreateCriação de registro.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
  3. RowErrors (OUTPUT): TempTable de Erros.

utp/ut-api-exec-update.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
UpdateAlteração de registro.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
  3. RowErrors (OUTPUT): TempTable de Erros.

utp/ut-api-exec-patch.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
PatchAlteração de registro.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
  3. RowErrors (OUTPUT): TempTable de Erros.

utp/ut-api-exec-delete.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
DeleteEliminação de registro.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. RowErrors (OUTPUT): TempTable de Erros.

utp/ut-api-exec-delete-list.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada.
DeleteListEliminação em lote.
  1. oInput (INPUT): Dados recebidos na requisição;
  2. aDeletedIdList (OUTPUT): Array da lista de Chaves dos Registros que foram Excluídos, no formato: [{key1:”xx”, keyN:”xx”}, {key1:”xx”, keyN:”xx”}];
  3. RowErrors (OUTPUT): TempTable de Erros.

utp/ut-api-exec-custom.i

  1. PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
  2. Programa de negócio a ser executado;
  3. PI interna do programa de negócio a ser executada;
  4. Tipo de Retorno do endpoint:
    • "Object" = O conteúdo retornado pelo programa de negócio será um Objeto;
    • "Array"  = O conteúdo retornado pelo programa de negócio será um Array.
  5. Código do Endpoint que será utilizado para envio para EPC.
Custom (NEG)Tratativa especifica de negócio.

Para Tipo de Retorno "Object":

  1. oInput (INPUT): Dados recebidos na requisição;
  2. oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
  3. RowErrors (OUTPUT): Tempable de Erros.

Para Tipo de Retorno "Array":

  1. oInput (INPUT): Dados recebidos na requisição;
  2. aResult (OUTPUT): Array retornado pelo programa de negócio;
  3. lHasNext (OUTPUT): Indicação se existem mais registros;
  4. RowErrors (OUTPUT): TempTable de Erros.

Observações

  • O programa de negócio informado será executado de forma persistente e executada a PI informada;
  • A Include irá utilizar a classe utilitária JsonAPIExecution para realizar a execução do programa de negócio;
  • As informações que serão envidas para a EPC, podem ser consultadas aqui


>>>>>Abaixo um exemplo de recurso desenvolvido em Progress ABL para ser utilizado junto ao serviço de API<<<<<<

No início do código estão todas as includes necessárias. O que vale ressaltar neste trecho é referente a include ut-api-action:

  • Nesta include são declaradas as procedures utilizadas na API, por exemplo: pi-send, pi-update.
  • Na mesma declaração é definido qual o método http aplicado, por exemplo: GET, POST, entre outros.
  • Em seguida é definido como o recurso será acessado pela URI, por exemplo: /~*/SEND
  • Isso significa que ao acessar a URI teremos algo como: http://host:port/dts/datasul-rest/resources/prg/sec/v1/users/send onde:

 


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}

{utp/ut-api-exec-custom.i pi-send    btb/progNeg.p pi-send-v1    "Array"  "sendEmail"}
{utp/ut-api-exec-update.i pi-update  btb/progNeg.p pi-update-v1}
{utp/ut-api-exec-get.i    pi-find    btb/progNeg.p pi-find-v1}
{utp/ut-api-exec-custom.i pi-default btb/progNeg.p pi-default-v1 "Object" "default"}
Programa de Negócio (btb/progNeg.p)
PROCEDURE pi-send-v1:
    DEFINE INPUT  PARAM oInput   AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAM aResult  AS JsonArray  NO-UNDO.
    DEFINE OUTPUT PARAM lHasNext AS LOGICAL    NO-UNDO.
    DEFINE OUTPUT PARAM TABLE FOR RowErrors.

    DEFINE VARIABLE oObject AS JsonObject NO-UNDO.

    aResult = NEW JsonArray().

    oObject = NEW JsonObject().
    oObject:ADD("teste",  "teste").
    oObject:ADD("teste1", "teste1").
    oObject:ADD("teste2", "teste2").
    aResult:ADD(oObject).

    oObject = NEW JsonObject().
    oObject:ADD("teste",  "teste").
    oObject:ADD("teste1", "teste1").
    oObject:ADD("teste2", "teste2").
    aResult:ADD(oObject).

    ASSIGN lHasNext = NO.
END.

PROCEDURE pi-update-v1:
    DEFINE INPUT  PARAM oInput  AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAM oOutput AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAM TABLE FOR RowErrors.

    oOutput = oInput.
END.

PROCEDURE pi-find-v1:
    DEFINE INPUT  PARAM oInput       AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAM oOutput      AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAM cExpandables AS CHARACTER  NO-UNDO.
    DEFINE OUTPUT PARAM TABLE FOR RowErrors.

    oOutput = NEW JsonObject().
    oOutput:ADD("method",      "GET").
    oOutput:ADD("procedure",   "pi-find").
    oOutput:ADD("description", "Test").

    ASSIGN cExpandables = "tabFilha1,tabFilha2".
END.

PROCEDURE pi-default-v1:
    DEFINE INPUT  PARAM oInput  AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAM oOutput AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAM TABLE FOR RowErrors.

    oOutput = NEW JSONObject().
    oOutput:ADD("method",      "GET").
    oOutput:ADD("procedure",   "pi-default").
    oOutput:ADD("description", "Test").
END.


     No exemplo acima, temos as seguintes includes utilitárias:


Algumas considerações sobre o uso da include de roteamento (ut-api-action):

  • Os roteamentos devem ser definidos do mais específico (detalhado) para o mais genérico (simples);
  • O utilitário faz uso da função MATCHES do Progress, que basicamente permite o uso do ponto "." (ponto) como coringa de uma determinada posição (1 caractere apenas) e o "*" (asterisco) para um conjunto de caracteres variáveis;
  • O caracter de escape "~" deve ser utilizado sempre que necessário, antecedendo caracteres especiais que comprometam a compilação do código progress;
  • Para definir mais de um parâmetro de pesquisa, utilize "," (vírgula) como separador. O processamento de mais de um parâmetro de pesquisa será sempre traduzido para usar o operador AND.
  • Permite o uso de todos métodos HTTP suportados pelo API Manager (GET, POST, PUT, DELETE, PATCH, ...)

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.



Classes utilitárias


Com o objetivo de facilitar a manipulação dos objetos JsonObject recebidos e enviados pela API Progress foram desenvolvidas algumas classes de utilitários:

  • JsonAPIRequestParser - Extrai informações do objeto JSON recebido como parâmetro da requisição;
  • JsonAPIResponse - Trata a criação do objeto JSON de response da requisição;
  • JsonAPIResponseBuilder - Trata a criação do objeto JSON de response da requisição através de um builder;
  • JsonAPIUtils - Utilitário com métodos que facilitam a manipulação de informações relacionados a API;
  • JsonAPIExecution - Classe utilizada para executar as API-REST de negócio, encapsulando toda tratativa de EPC, controle de ERRO e padronizando o retorno das informações para o FrontEnd;
  • JsonAPIQueryUtils - Classe utilizada montagem de Querys dinâmicas, considerando o padrão TotvsAPI (filtro simples, complexo (odata), ordenação, etc...).



Formato Mensagem JSON


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.

Com esta 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: ...}]
}



Acesso a Diferentes Empresas


O cliente pode fazer acesso a diferentes empresas via BASIC AUTHENTICATION. Para realizar esse processo é necessário primeiramente o login no sistema, e em seguida descobrir todas as empresas do produto, selecionando um dos links a seguir: 

  • (JBoss ou Tomcat): http://<host>:<port>/api/btb/v1/companies
  • (JBoss): http://<host>:<port>/dts/datasul-rest/resources/btb/v1/companies
  • (Tomcat): http://<host>:<port>/dts/datasul-rest/resources/prg/btb/v1/companies


Atenção

Os links acima retornam todas as empresas do produto, então se faz necessário verificar que a empresa utilizada realmente possui vínculo com o usuário logado no sistema, uma vez que não existe controle de vinculo entre empresa e usuário.

Se atente aos campos host e port no link, esses deverão ser modificados pelo usuário de acordo com o ambiente utilizado.

Em novas implementações, de preferência ao endpont com o contexto /api.


A partir do momento que se sabe qual empresa se deseja enviar na requisição e que a mesma está associada ao usuário, é possível fazer a chamada da API que desejar, passando o código como parâmetro dentro do atributo companyId, esse especificado dentro do Header.



GET /api/btb/v1/companies HTTP/1.1
Host: host:port
companyId: 10
Authorization: Basic MTM6MTM=

Informação

A requisição para a API pode ser feita pela ferramenta Postman ou por outra ferramenta que de suporte a requisições feitas pela API.



Login


Na Antiga Arquitetura (Jboss) para realizar o login no contexto DTS/DATASUL-REST (apesar de existir BASIC AUTHENTICATION com o contexto /api), ainda é possível passar como parâmetro usuário e senha para na seguinte URL.

URL para Login

http://localhost:8180/dts/datasul-rest/resources/login?username=<USER>&password=<PASSWORD>

Aviso importante!

Caso a sua aplicação/portal esteja em um servidor diferente do JBOSS Datasul, será necessário informar a propriedade portal.java.naming.security.datasulurl no arquivo datasul_framework.properties conforme exemplo abaixo:
portal.java.naming.security.datasulurl=http://<servidor JBoss Datasul>:<porta>
Isso é necessário pois o login deverá ser feito no servidor JBOSS do Datasul e não no servidor da aplicação/portal.

Para passagem da senha deve ser em Lower Case e é necessário converte-la para SHA1 (utilizando Byte Array), 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.

  • Senha: testPassword
  • BASE64(SHA1): i7YRj4/Wk1rQh2o740pxfTJwj/0=
  • URL-ENCODE: i7YRj4%2FWk1rQh2o740pxfTJwj%2F0%3D

Observe que por trazer os caracteres " / e = " na conversão de SHA1 e BASE64, é necessário o URL-ENCODE.

Sugestão para URL-ENCODE: https://meyerweb.com/eric/tools/dencoder/


Exemplo de Conversão
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

Aviso importante!

Para realizar esse encode NÃO pode utilizar codificação HEXADECIMAL, caso que acontece no Java (processo interno da linguagem), então é preciso utilizar o Byte Array!

Exemplo de URL final

http://localhost:8180/dts/datasul-rest/resources/login?username=teste&password=i7YRj4%2FWk1rQh2o740pxfTJwj%2F0%3D



Para o servidor de aplicação JBOSS é possível realizar a autenticação via BASIC authentication através de duas maneiras 1) por endpoint REST ou 2) pelo componente JOSSO.

ATENÇÃO

Em caso de erro no login por troca do HTTP METHOD de POST para GET ou vice e versa. Será obrigatório o uso do login via componente JOSSO explicado abaixo!

A chamada com header http BASIC no produto Datasul é possível ser feita diretamente na chamada do endpoint. Basta informar corretamente o HEADER e realizar a request.

EXEMPLO-1: chamando o endpoint http://host:port/dts/datasul-rest/resources/btb/v1/companies

Chamada BASIC datasul-rest
GET dts/datasul-rest/resources/btb/v1/companies HTTP/1.1
Host: host
...
Origin: http://host:port
Authorization: BASIC Z3VpdGE6Z3VpdGE=

EXEMPLO-2: chamando o endpoint http://host:port/api/btb/v1/companies

Chamada BASIC api
GET api/btb/v1/companies HTTP/1.1
Host: host
...
Origin: http://host:port
Authorization: BASIC Z3VpdGE6Z3VpdGE=

Em ambo os caso a codificação BASIC é construída com a notação BASE64(username:password)

A chamada com header http BASIC no produto Datasul através do componente JOSSO é feita diretamente na chamada do endpoint de autenticação. Basta informar corretamente o HEADER e realizar a request.

EXEMPLO: chamando o endpoint de autenticação http://host:port/josso/signon/auth.do com BASIC

Request BASIC
GET josso/signon/auth.do HTTP/1.1
Host: host
...
Origin: http://host:port
Authorization: BASIC Z3VpdGE6Z3VpdGE=
Response
{
 "status":"200",
 "description":"Login Authorized - Token Generated",
 "JOSSO_SESSIONID":"C7C4669F68BB35995C4BE13142769FA3",
 "JWT":""
}

Neste caso basta captura o JSON de retorno acima e utilizar o JOSSO_SESSIONID nas demais requisições. Lembrando que a codificação BASIC é construída com a notação BASE64(username:password)

Para acessar o produto DTS4THF com apis devemos utilizar o formato BASIC do http. Para saber mais clique aqui



Logout



Para a arquitetura do JBOSS é possível realizar o logout via as chamadas REST. Isso pode ser feito para que os contextos de trabalho com o josso sejam liberados e que a session seja invalidada no fechamento dos APPs.

Desta maneira, existe a seguinte url para realizar o logout no produto via chamada REST.


Chamar URL de logout
Contexto api
http://host:port/api/logout

Contexto dts/datasul-rest
http://host:port/dts/datasul-rest/resources/logout