Objetivo
Apresentar a documentação dos recursos da API Totvs-REST para serem utilizados por outras aplicações do Datasul. Ao oferecer de forma encapsulada esses recursos para que outras aplicações possam acessá-los, torná-se possível o Reuso, a Centralização e Integração:
- Reuso de lógicas, uma vez que ao expor um método ou uma função por exemplo, o código do respectivo não precisa ser duplicado no contexto da solução;
- Centralizar lógica (premissa para coesão) que viabiliza em um único ponto de uma solução o acesso a tal lógica;
- Viabilizar integração com outras aplicações quando se tata de uma integração em “baixo nível”, o que causa demanda de acesso a recursos internos da aplicação.
Para modelar a estrutura da documentação será utilizada a ferramentaSWAGGER
que, neste contexto faz uso do formatoYAML
de serialização de dados.
Semântica dos métodos HTTP
No universo REST, uma requisição HTTP pode-se dizer que é equivalente a uma chamada de uma 'procedure' progress.
O método HTTP é utilizado para determinar a operação a ser realizada em um determinado recurso. Em geral, utiliza-se:
- GET - método para recuperação de dados,
- POST - método para para inserir dados,
- PUT - método para alterar dados existentes e
- DELETE - método para apagar dados;
Exemplo de Documentação para API Totvs-REST
O Parser SWAGGER realizará a leitura de um arquivo externo, em formato YAML e validará o conteúdo apontado para um arquivo PROGRESS. O resultado do "parseamento" será um arquivo em formato JSON.
Para elucidar a utilização da API Totvs-Rest segue um exemplo de como realizar as chamadas utilizando o 'SWAGGER
' para gerar a documentação. Assim, o exemplo seguirá sempre o padrão: Bloco 'SWAGGER
' (do arquivo *.yml) seguido de seu bloco 'PROGRESS
' correspondente (do arquivo *.p), nesta sequência.
Para o exemplo prático foi utilizada uma simulação de "Manipulação de Pedidos".
Segue abaixo os blocos de códigos documentados:
INFO
Arquivo *.yml:
Inicialmente é informada a versão do Swagger
, na própria seção 'swagger'. Na seção 'info' estão as informações da descrição (description
), a versão da API (version
) e o título (title
).
Na seção basePath
colocamos o contexto da aplicação.
Na seção tags
se nomeia o serviço (name
), a descrição do serviço (description
) e os documentos externos (externaldocs
), caso existam, com a descrição e o link de acesso (url
).
A tag principal desse bloco é 'program'
e referencia o arquivo *.p que precisar ser documentado, ou seja, no exemplo abaixo o arquivo *.yml validará o arquivo PROGRESS
'pedido.p'.
swagger: "2.0" info: description: "Este é um exemplo de aplicação de API no modelo Totvs-rest para um modelo de negocio referente a 'Pedidos'" version: "1.0.0" title: "Exemplo API Totvs-REST" basePath: "/tstUn/v1/" program: pedido.p tags: - name: "servicoConsultaPedido" description: "Exemplopo de chamada para modelo de negócio 'Pedido'" externalDocs: description: "Mais informações em:" url: "http://tdn.totvs.com" schemes: - "http" paths: /tstUniApiDatasul:
Arquivo *.p:
No bloco de código PROGRESS
abaixo (pedido.p), estão inicialmente as chamadas das includes progress
referente a padronização das ações dos métodos HTTP
. Este trecho não é correspondente ao YAML acima, porém complementa a construção da API TOTVS-REST.
{utp/ut-api.i} {utp/ut-api-action.i pi-get GET /~* } {utp/ut-api-action.i pi-send GET /~*/SEND by=email,address=~* } {utp/ut-api-action.i pi-post POST /~* oi=1} {utp/ut-api-action.i pi-put PUT /~* } {utp/ut-api-action.i pi-delete DELETE /~* } {utp/ut-api-notfound.i}
GET
Arquivo *.yml:
A seguir a documentação referente ao método GET para listar os pedidos existentes. A documentação informa que o recurso acessado será "pedido".
Dentro da seção get
estão contidas todas a sub seções que compõem a modelagem do recurso desse método (podem haver mais recursos). Assim sendo, na seção tags
está definido o path do recurso 'pedido' para montagem da URI: .../tst/v1//tstUniApiDatasul/pedido
Ao enviar a requisição pode-se informar, como parâmentros (na sub seção parameters
), filtros do status do pedido dentro da sub seção items
.
O retorno da requisição, sub seção produces
, será um JSON contendo a lista filtrada dos pedidos existentes na base de dados junto com o status (responses
) 200 que informa que a operação foi executada com sucesso.
A validação neste método acontece na declaração da procedure progress, na tag 'procedure
', que neste caso é 'pi-get'.
get: procedure: pi-get tags: - "pedido" summary: "Busca Dados dos pedidos existentes" description: "Busca os dados dos pedidos cadastrados na base de dados" operationId: "getPedido" produces: - "application/json" parameters: - name: "status" in: "query" description: "Valores de status que precisam ser considerados para o filtro dos pedidos. Ex: available, pending e/ou sold" required: true type: "array" items: type: "string" enum: - "available" - "pending" default: "available" collectionFormat: "multi" responses: 200: description: "Operação executada com sucesso" schema: type: "array" items: $ref: "#/definitions/payloadDeRetornoPedido"
Arquivo *.p:
No arquivo progress a procedure correspondente apresenta a efetivação da ação com os dados de entrada e retorno da requisição em um objeto JSON.
PROCEDURE pi-get: DEF INPUT PARAM jsonInput AS JsonObject NO-UNDO. DEF OUTPUT PARAM jsonOutput AS JsonObject NO-UNDO. ASSIGN jsonOutput = jsonInput. END.
POST
Arquivo *.yml:
A documentação seguinte refere-se ao cadastro de uma nova informação/registro na base e, para isso, utiliza o método POST.
No mesmo recurso "pedido", serão enviados os dados envelopados em um código JSON (sub seção consumes
) e o mesmo será retornado na resposta da requisição (sub seção produces
) como comprovação de que os dados foram gravados.
A validação neste método acontece na declaração da procedure progress, na tag 'procedure
', que neste caso é 'pi-post'.
post: procedure: pi-post tags: - "pedido" summary: "Cadastro de um novo pedido" description: "Envia dados de um novo cadastro de pedido para a base de dados utilizando o método POST" operationId: "addPedido" consumes: - "application/json" produces: - "application/json" parameters: - in: "body" name: "body" description: "Parâmetros necessários enviados no 'payload' para adicionar o novo pedido" required: true schema: $ref: "#/definitions/payloadEnvioPedido"
Arquivo *.p:
No arquivo progress a procedure correspondente, assim como no método GET, apresenta a efetivação da ação com os dados de entrada e retorno da requisição em um objeto JSON.
PROCEDURE pi-post: DEF INPUT PARAM jsonInput AS JsonObject NO-UNDO. DEF OUTPUT PARAM jsonOutput AS JsonObject NO-UNDO. ASSIGN jsonOutput = jsonInput. END.
PUT
Arquivo *.yml:
A próxima documentação apresenta o método PUT, quando há necessidade de alteração e/ou atualização de algum registro existente.
Assim como o método POST, também encapsula os dados em um código JSON para atualizar os dados desejados (sub seção consumes
), porém pode também informar essa atualização como parâmetros na URI.
A validação neste método acontece na declaração da procedure progress, na tag 'procedure
', que neste caso é 'pi-put'.
put: procedure: pi-put tags: - "pedido" summary: "Atualiza um registro existente de pedido" description: "Atualiza os dados de um registro de pedido existente na base de dados utilizando o método Put" operationId: "putPedido" consumes: - "application/json" produces: - "application/json" parameters: - in: "body" name: "body" description: "Parâmetros necessários enviados no 'payload' para atualizar um pedido existente" required: true schema: $ref: "#/definitions/payloadEnvioPedido"
Arquivo *.p:
No arquivo progress a procedure correspondente, assim como no método GET e POST, apresenta a efetivação da ação com os dados de entrada e retorno da requisição em um objeto JSON (sub seção produces
).
PROCEDURE pi-put: DEF INPUT PARAM jsonInput AS JsonObject NO-UNDO. DEF OUTPUT PARAM jsonOutput AS JsonObject NO-UNDO. ASSIGN jsonOutput = jsonInput. END.
DELETE
Arquivo *.yml:
A documentação para o método DELETE informa que para executar a exclusão de um registro é preciso passar como parâmetro na URI uma chave na sub seção parameters
.
Como retorno, também apresenta um JSON contendo as informações do registro excluído na sub seção produces
.
A validação neste método acontece na declaração da procedure progress, na tag 'procedure
', que neste caso é 'pi-delete'.
delete: procedure: pi-delete tags: - "pedido" summary: "Exclui um pedido existente" description: "Realiza a exlusão de um pedido existente na base de dados utilizando o método PUT" operationId: "deletePedido" produces: - "application/json" parameters: - name: "api_key" in: "header" required: false type: "string" - name: "petId" in: "path" description: "Parâmetros necessários enviados no 'payload' para exlcuir um pedido existente" required: true type: "integer" format: "int64"
Arquivo *.p:
No arquivo progress a procedure correspondente, assim como nos métodos anteriores, apresenta a efetivação da ação com os dados de entrada e retorno da requisição em um objeto JSON.
PROCEDURE pi-delete: DEF INPUT PARAM jsonInput AS JsonObject NO-UNDO. DEF OUTPUT PARAM jsonOutput AS JsonObject NO-UNDO. ASSIGN jsonOutput = jsonInput. END.
DEFINITIONS
Ainda no arquivo YAML existe a seção definitions
onde é realizada a definição do modelo de dados com os objetos, assim sendo, no exemplo abaixo, foram definidos objetos payload para envio e retorno de pedidos.
Dentro de cada objeto foi estabelecido o tipo (sub seção type
) e as propriedades (sub seção properties
) pertinentes a cada um.
definitions: payloadEnvioPedido: type: "object" required: - "numeroPedido" - "codigoCliente" properties: id: type: "integer" format: "int64" numeroPedido: type: "integer" example: "ped123456879" format: "int64" codigoCliente: type: "string" description: "cliente1234" descricaoCliente: type: "string" example: "Cliente de Teste" payloadDeRetornoPedido: type: "object" properties: id: type: "integer" format: "int64" numeroPedido: type: "integer" example: "ped123456879" format: "int64" statusDoPedido: type: "string" description: "Pedido Aprovado" enum: - "Aprovado" - "Reprovado"
Restrição:
Comentários tanto em linha (#) com em bloco (/**/) não serão validados, ou seja, o parser realizará a leitura independente da existência ou não dos comentários.