Serviço Progress
Para
fnd| Expandir |
|---|
| title | Clique para visualizar o conteúdo |
|---|
|
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) |
. A .
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.: | Aviso |
|---|
Os programas Progress disponibilizados, deverão seguir o padrão de localização abaixo e devem estar compilados, ou seja, é necessário o *.r |
|
| Aviso |
|---|
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 feita 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 |
através das utilizando as includes utilitárias disponibilizadas: | Include | Parâmetros da Include | Descrição |
|---|
utp/ut-api.i |
|
: | Não há. | Faz o parser do parâmetro LONGCHAR de entrada e cria um objeto JsonObject |
|
chamado | chamado jsonInput. | | utp/ut-api-action.i |
|
: | - Nome da procedure interna que deve ser executada.
- Método da Requisição.
- Rota.
| Faz o roteamento do |
|
objecto | 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. |
|
Abaixo um exemplo de recurso desenvolvido em Progress ABL para ser utilizado junto ao serviço de API:
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: |
| Bloco de código |
|---|
{| Include | Parâmetros da Include | Endpoint | Descrição | Parâmetros enviado para PI Interna |
|---|
.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 /~* }
{-exec-metadata.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| Metadata | Devolve metadata para geração das telas. | - oInput (INPUT): Dados recebidos na requisição;
- cEvent (INPUT): Evento solicitado pelo Front (list, new, edit, copy ou detail);
- cVersion (INPUT): Versão solicitada pelo Front;
- oOutput (OUTPUT): Objeto de Metatadata;
- RowErrors (OUTPUT): TempTable de Erros.
| 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.
| Informações |
|---|
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, ...)
|
| Informações |
|---|
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:
| Bloco de código |
|---|
|
{
uri: valor,
method: GET,
headers: {},
pathParams: [ "param1", "param2" ],
queryParams: { query1: [valor1, valor2], query2: [valor1]},
payload: { },
multyPartFile: [ {file: ...}, {file: ...}]
} |
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
Login
Para realizar o login no DATASUL-REST é necessário passar como parâmetro usuário e senha na seguinte URL.
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.
- 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.
| Bloco de código |
|---|
| title | Exemplo de Conversão |
|---|
| linenumbers | true |
|---|
|
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 |
exec-vld-form.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| VldForm | Validação de formulário. | - oInput (INPUT): Dados recebidos na requisição;
- oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
- RowErrors (OUTPUT): TempTable de Erros.
| utp/ut-api-exec-vld-field.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| VldField | Validação de campo. | - oInput (INPUT): Dados recebidos na requisição;
- oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
- RowErrors (OUTPUT): TempTable de Erros.
| utp/ut-api-exec-get.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| Get | Busca um registro. | - oInput (INPUT): Dados recebidos na requisição;
- oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
- cExpandables (OUTPUT): Lista de entidades "filhas" separadas por vírgula;
- RowErrors (OUTPUT): Tempable de Erros.
| utp/ut-api-exec-query.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| Query | Busca vários registros. | - oInput (INPUT): Dados recebidos na requisição;
- aResult (OUTPUT): Array retornado pelo programa de negócio;
- lHasNext (OUTPUT): Indicação se existem mais registros;
- cExpandables (OUTPUT): Lista de entidades "filhas" separadas por vírgula;
- RowErrors (OUTPUT): TempTable de Erros.
| utp/ut-api-exec-create.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| Create | Criação de registro. | - oInput (INPUT): Dados recebidos na requisição;
- oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
- RowErrors (OUTPUT): TempTable de Erros.
| utp/ut-api-exec-update.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| Update | Alteração de registro. | - oInput (INPUT): Dados recebidos na requisição;
- oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
- RowErrors (OUTPUT): TempTable de Erros.
| utp/ut-api-exec-patch.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| Patch | Alteração de registro. | - oInput (INPUT): Dados recebidos na requisição;
- oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
- RowErrors (OUTPUT): TempTable de Erros.
| utp/ut-api-exec-delete.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| Delete | Eliminação de registro. | - oInput (INPUT): Dados recebidos na requisição;
- RowErrors (OUTPUT): TempTable de Erros.
| utp/ut-api-exec-delete-list.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada.
| DeleteList | Eliminação em lote. | - oInput (INPUT): Dados recebidos na requisição;
- aDeletedIdList (OUTPUT): Array da lista de Chaves dos Registros que foram Excluídos, no formato: [{key1:”xx”, keyN:”xx”}, {key1:”xx”, keyN:”xx”}];
- RowErrors (OUTPUT): TempTable de Erros.
| utp/ut-api-exec-custom.i | - PI interna a ser definida no programa (a mesma informada na include de rota correspondente);
- Programa de negócio a ser executado;
- PI interna do programa de negócio a ser executada;
- 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.
- Código do Endpoint que será utilizado para envio para EPC.
| Custom (NEG) | Tratativa especifica de negócio. | Para Tipo de Retorno "Object": - oInput (INPUT): Dados recebidos na requisição;
- oOutput (OUTPUT): Objeto retornado pelo programa de negócio;
- RowErrors (OUTPUT): Tempable de Erros.
Para Tipo de Retorno "Array": - oInput (INPUT): Dados recebidos na requisição;
- aResult (OUTPUT): Array retornado pelo programa de negócio;
- lHasNext (OUTPUT): Indicação se existem mais registros;
- RowErrors (OUTPUT): TempTable de Erros.
|
| Informaçõ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<<<<<< | Expandir |
|---|
| title | Clique para visualizar o exemplo ... |
|---|
| 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:
| draw.io Diagram |
|---|
| border | true |
|---|
| viewerToolbar | true |
|---|
| fitWindow | false |
|---|
| diagramName | estrutura |
|---|
| simpleViewer | false |
|---|
| width | 600 |
|---|
| links | auto |
|---|
| tbstyle | top |
|---|
| lbox | true |
|---|
| diagramWidth | 785 |
|---|
| revision | 5 |
|---|
|
| Bloco de código |
|---|
| language | ruby |
|---|
| theme | Eclipse |
|---|
| title | 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"} |
| Bloco de código |
|---|
| language | ruby |
|---|
| theme | Eclipse |
|---|
| title | 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: | draw.io Diagram |
|---|
| border | true |
|---|
| viewerToolbar | true |
|---|
| fitWindow | false |
|---|
| diagramName | utilitarios |
|---|
| simpleViewer | false |
|---|
| diagramWidth | 1079 |
|---|
| revision | 5 |
|---|
|
| Informações |
|---|
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, ...)
|
| Informações |
|---|
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. |
|