Já pensou em integrar suas aplicações com o ERP Protheus ?
O Protheus, como vários ERP’s, são sistemas muito completos e que abrange diversas áreas da empresa, porém sabemos que muitos desses ERP’s não tem acompanhado as novas aplicações de mercado, principalmente na área web/mobile.
Mas enquanto as grandes desenvolvedoras adequam seus ERP’s para essa nova geração tecnológica, podemos muito bem fazer os grandes e arcaicos ERP’s conversarem com ferramentas mais amigáveis, dessa forma unimos o melhor de cada uma das tecnologias para otimizar os trabalhos.
O Protheus contempla algumas formas de realizar integração, como:
Webservice SOAP
EAI Próprio
Webservice Rest
Em minha concepção o mais aderente as plataformas existentes no mercado é o webservice Rest que possui sua representação em JSON e por padrão TOTVS já possui sua camada interface e de autenticação bem implementadas.
Passos necessários para preparar seu Protheus para funcionar com o Webservice Rest:
Configurar um server de webservice Rest
Para realizar a configuração será necessário adicionarmos alguns itens no arquivo .ini do server Protheus. Sugiro que seja criado um server separado para o Webservice, tanto por questão de performance, como também por questão de manutenção.
[GENERAL]
MAXSTRINGSIZE=10
[HTTPV11]
Enable=1
Sockets=HTTPREST
[HTTPREST]
Port=8080
URIs=HTTPURI
SECURITY=1
[HTTPURI]
URL=/rest
PrepareIn=All
Instances=1,2
[ONSTART]
jobs=HTTPJOB
RefreshRate=30
[HTTPJOB]
MAIN=HTTP_START
ENVIRONMENT=environment
Desenvolvendo sua Classe Rest ADVPL
Para começarmos a desenvolver nossa Primeira classe Rest em ADVPL vamos precisar entender um pouco a ideia dos verbos existentes nesta representação:
- POST – Verbo responsável por realizar inclusões de registros no sistema.
- PUT – Verbo responsável por realizar alterações de registros no sistema.
- GET – Verbo responsável por realizar o retorno de registros do sistema.
- DELETE – Verbo responsável por realizar exclusões de registros do sistema.
Definidas as responsabilidades de cada método podemos começar a exemplificar cada um deles.
Para isso, primeiro precisamos a construir a estrutura base do nosso fonte ADVPL para nossa classe Rest.
#Include 'Protheus.ch'
#Include 'RestFul.CH' //Necessario utilizar a incluide do RESTFUL
/*/-----------------------------------------------------------
{Protheus.doc} WsRstExp()
Dummy function da Classe Rest
Esta função é necessario pois o ADVPL necessita de um function
dentro do fonte
Uso: WsRstExp
@sample
//U_WsRstExp()
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
User Function WsRstExp()
Return
/*/-----------------------------------------------------------
{Protheus.doc} WsRstExp()
Definição da Classe, propriedades e assinatura dos métodos
Uso: WsRstExp
@sample
//U_WsRstExp()
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSRESTFUL WsRstExp DESCRIPTION "Serviço REST de exemplo"
WSDATA param1 As STRING
WSDATA param2 As STRING Optional
WSMETHOD GET DESCRIPTION "Get Exemplo" WSSYNTAX "/WsRstExp?param1={valueParam1}¶m2={valueParam2}"
WSMETHOD POST DESCRIPTION "Post Exemplo" WSSYNTAX "/WsRstExp"
WSMETHOD PUT DESCRIPTION "Put Exemplo" WSSYNTAX "/WsRstExp?param1={valueParam1}¶m2={valueParam2}"
WSMETHOD DELETE DESCRIPTION "Delete Exemplo" WSSYNTAX "/WsRstExp?param1={valueParam1}¶m2={valueParam2}"
END WSRESTFUL
No exemplo acima definimos a classe
WsRstExp, na sequencia definimos 2 parâmetros sendo um deles como opicional.
Em seguida definimos a assinatura dos 4 métodos que serão utilizados.
Na definição da assinatura temos a seguinte estrutura:
WSMETHOD <cVerb> [cId]
DESCRIPTION <cDescription> [
WSSYNTAX <cSintax>] [
PATH <cPath>] [
TTALK <cTTalkVersion>]
Na definição do método temos a seguinte estrutura:
WSMETHOD <cVerb> [cId] [
QUERYPARAM <QueryParms>] [
PATHPARAM <PathParms>] [
HEADERPARAM <HeaderParms>]
WSRESTFUL <WsRestFul>
Nome |
Tipo |
Descrição |
Obrigatório |
cVerb |
– |
POST, PUT, GET ou DELETE |
X |
cId |
Caracter |
ID para diferenciar e possibilitar a criação de métodos que utilizam verbos http repetidos |
|
cDescription |
Caracter |
Descrição do método REST |
X |
cSintax |
Caracter |
Sintaxe HTTP da chamada REST. Esta informação é utilizada apenas para documentação do REST. |
|
cPath |
Caracter |
Definição do endpoint que irá acionar aquele método. |
|
*Pode conter agrupamento, o nome da classe e os pathparms. (A partir da release 12.1.23 da lib, em jan./2019). |
cTTalkVersion |
Caracter |
Valor “v1” para sinalizar que o método utiliza o padrão de mensagem de erro do TTALK. |
|
QueryParms |
– |
Indica os parâmetros, separados por vírgulas, que este método receberá via QueryString. |
|
O parâmetros indicados aqui devem ser declarados como WSDATA. |
PathParms |
– |
Indica os parâmetros, separados por vírgulas, que este método receberá via path, ou seja, como parte da URL. |
|
HeaderParms |
– |
Indica os parâmetros, separados por vírgulas, que este método receberá via Header na requisição HTTP. |
|
WsRestFul |
Caracter |
Indica o nome da classe, do serviço, que o método atual pertence. |
X |
Agora vamos começar a definir os métodos logo abaixo do código anterior:
/*/-----------------------------------------------------------
{Protheus.doc} GET
Get de Exemplo - Método utilizado para consultas
Uso: WsRstExp
@sample
//GET / WsRstExp
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSMETHOD GET WSRECEIVE param1, param2 WSSERVICE WsRstExp
Local lRet := .T. // Recebe o Retorno
Local oJsonRet := NIL // Recebe o JSON de Saida
/*
Trecho com a sua codificação
*/
// Monta Objeto JSON de retorno
oJsonRet := NIL
oJsonRet := JsonObject():new()
oJsonRet['Propriedade1'] := EncodeUTF8("Retorno 1", "cp1252")
oJsonRet['Propriedade2'] := 10
oJsonRet['Propriedade3'] := .T.
// Devolve o retorno para o Rest
::SetResponse(oJsonRet:toJSON())
Return lRet
/*/-----------------------------------------------------------
{Protheus.doc} POST
Post de Exemplo - Método utilizado para inclusões
Uso: WsRstExp
@sample
//POST/ WsRstExp
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSMETHOD POST WSRECEIVE nullparam WSSERVICE WsRstExp
Local lRet := .T. // Recebe o Retorno
Local cBody := '' // Recebe o conteudo do Rest
Local oJson := NIL // Recebe o JSON de Entrada
Local oJsonRet := NIL // Recebe o JSON de Saida
// Pega o conteudo JSON da transação Rest
cBody := ::GetContent()
::SetContentType("application/json")
oJson := JsonObject():new()
oJson:fromJson(cBody)
/*
Trecho com a sua codificação
*/
// Monta Objeto JSON de retorno
oJsonRet := NIL
oJsonRet := JsonObject():new()
oJsonRet['Propriedade1'] := EncodeUTF8("Retorno 1", "cp1252")
oJsonRet['Propriedade2'] := 10
oJsonRet['Propriedade3'] := .T.
// Devolve o retorno para o Rest
::SetResponse(oJsonRet:toJSON())
FreeObj(oJsonRet)
FreeObj(oJson)
Return lRet
/*/-----------------------------------------------------------
{Protheus.doc} PUT
PUT de Exemplo - Método utilizado para Alterações
Uso: WsRstExp
@sample
//PUT / WsRstExp
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSMETHOD PUT WSRECEIVE param1, param2 WSSERVICE WsRstExp
Local lRet := .T. // Recebe o Retorno
Local cBody := '' // Recebe o conteudo do Rest
Local oJson := NIL // Recebe o JSON de Entrada
Local oJsonRet := NIL // Recebe o JSON de Saida
// Pega o conteudo JSON da transação Rest
cBody := ::GetContent()
::SetContentType("application/json")
oJson := JsonObject():new()
oJson:fromJson(cBody)
/*
Trecho com a sua codificação
*/
// Monta Objeto JSON de retorno
oJsonRet := NIL
oJsonRet := JsonObject():new()
oJsonRet['Propriedade1'] := EncodeUTF8("Retorno 1", "cp1252")
oJsonRet['Propriedade2'] := 10
oJsonRet['Propriedade3'] := .T.
// Devolve o retorno para o Rest
::SetResponse(oJsonRet:toJSON())
FreeObj(oJsonRet)
FreeObj(oJson)
Return lRet
/*/-----------------------------------------------------------
{Protheus.doc} DELETE
DELETE de Exemplo - Método utilizado para exclusões
Uso: WsRstExp
@sample
//DELETE / WsRstExp
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSMETHOD DELETE WSRECEIVE param1, param2 WSSERVICE WsRstExp
Local lRet := .T. // Recebe o Retorno
Local cBody := '' // Recebe o conteudo do Rest
Local oJson := NIL // Recebe o JSON de Entrada
Local oJsonRet := NIL // Recebe o JSON de Saida
// Pega o conteudo JSON da transação Rest
cBody := ::GetContent()
::SetContentType("application/json")
oJson := JsonObject():new()
oJson:fromJson(cBody)
/*
Trecho com a sua codificação
*/
// Monta Objeto JSON de retorno
oJsonRet := NIL
oJsonRet := JsonObject():new()
oJsonRet['Propriedade1'] := EncodeUTF8("Retorno 1", "cp1252")
oJsonRet['Propriedade2'] := 10
oJsonRet['Propriedade3'] := .T.
// Devolve o retorno para o Rest
::SetResponse(oJsonRet:toJSON())
FreeObj(oJsonRet)
FreeObj(oJson)
Return lRet
Nos exemplos acima utilizei a Classe
JsonObject para tratar dados do tipo JSON, com a mesma é possivel transformar o JSON para objeto e vice-versa.
Muito importante
Para realizar os retornos para o Webservice Rest, temos dois métodos que precisamos utilizar.
Em caso de sucesso e vamos devolver um JSON com conteúdo, utilizamos o método
::SetResponse(“[JSON]”).
Em caso de falha utilizamos o método
SetRestFault([StatusErro]), EncodeUTF8(“[Mensagem de Erro]”, “cp1252”)).
Observação : utilizo a função
EncodeUTF8(“Texto”, “cp1252”), para suprimir problemas de acentuação ao utilizar o envio de textos pela WS Rest.
Nos casos de falha podemos utilizar a tabela abaixo para definir o StatusErro:
Status HTTP |
Descrição |
422 |
Exceções de negócio |
400 |
Requisição Mal Formada |
401 |
Requisição Requer Autenticação |
403 |
Requisição Negada |
404 |
Recurso não Encontrado |
405 |
Método não Permitido |
408 |
Tempo esgotado para a requisição |
413 |
Requisição excede o tamanho máximo permitido |
415 |
Tipo de mídia inválida (falta de informar o content-type correto, ver JSON) |
429 |
Requisição excede a quantidade máxima de chamadas permitidas à API |
500 |
Erro de servidor |
Vou deixar aqui a documentação da TOTVS com mais algumas informações importantes sobre toda a estrutura do REST.
https://tdn.totvs.com/display/framework/REST+ADVPL
https://tdn.totvs.com/pages/viewpage.action?pageId=75269436
É isso pessoal.
Espero que ajude muito vocês.
Até a próxima!!!