Visão geral: Criando um Webservice RESTful no Protheus
##
Estrutura básica do Webservice REST
#INCLUDE "PROTHEUS.CH"
#INCLUDE "RWMAKE.CH"
#INCLUDE "TBICONN.CH"
#INCLUDE "COLORS.CH"
#INCLUDE "RPTDEF.CH"
#INCLUDE "FWPrintSetup.ch"
#Include 'parmtype.ch'
#Include "RestFul.CH"
#Include "TopConn.CH"
#INCLUDE "FILEIO.ch"
User Function FBESTA01()
Return
WSRESTFUL CONSESTQ DESCRIPTION "Serviço REST para consulta de estoque"
WSDATA SEGKEY As String
WSDATA PFILIAL As String
WSDATA PRODUTO As String
WSDATA ARMAZEM As String
WSMETHOD GET DESCRIPTION "Retorna o estoque do produto informado na URL"
WSSYNTAX "/CONSESTQ || /CONSESTQ/{PFILIAL}{PRODUTO}{ARMAZEM}"
END WSRESTFUL
###
Principais pontos dessa estrutura
- WSRESTFUL: Define a classe do Webservice.
- WSDATA: Mapeia os parâmetros que serão recebidos via URL.
- WSMETHOD GET: Define o método HTTP e a rota que será exposta.
##
Tratamento da Requisição GET
WSMETHOD GET WSSERVICE CONSESTQ
Local cPFILIAL := Self:PFILIAL
Local cPRODUTO := Self:PRODUTO
Local cARMAZEM := Self:ARMAZEM
Local aArea := GetArea()
Local cJson := ""
Local aDados := {}
If !u_FBSegApp(Self:SEGKEY)
Return
EndIf
::SetContentType("application/json")
aDados := u_FBESTA02(cPFILIAL, cPRODUTO, cARMAZEM, "SB2.B2_COD")
oObjCom := Objetos():New(aDados)
cJson := FWJsonSerialize(oObjCom)
::SetResponse(cJson)
RestArea(aArea)
Return(.T.)
###
O que está acontecendo aqui?
- Validação da chave de segurança com `u_FBSegApp`.
- Chamada da função `FBESTA02`, responsável pela consulta de dados.
- Serialização dos dados usando `FWJsonSerialize`.
- Resposta JSON formatada enviada ao cliente via `SetResponse`.
##
Consulta ao banco de dados: a função FBESTA02
User Function FBESTA02(cPFILIAL, cPRODUTO, cARMAZEM, cOrderBy)
Local aRet := {}
Local cFiltro := ""
If !Empty(cPFILIAL)
cFiltro += " AND SB2.B2_FILIAL = '" + cPFILIAL + "' "
EndIf
If !Empty(cPRODUTO)
cFiltro += " AND SB2.B2_COD = '" + UPPER(cPRODUTO) + "' "
EndIf
If !Empty(cARMAZEM)
cFiltro += " AND SB2.B2_LOCAL = '" + cARMAZEM + "' "
EndIf
// Aqui você pode continuar explicando e depois incluir o código completo original como solicitado
##
Implementação Completa
#INCLUDE "PROTHEUS.CH"
#INCLUDE "RWMAKE.CH"
#INCLUDE "TBICONN.CH"
#INCLUDE "COLORS.CH"
#INCLUDE "RPTDEF.CH"
#INCLUDE "FWPrintSetup.ch"
#Include 'parmtype.ch'
#Include "RestFul.CH"
#Include "TopConn.CH"
#INCLUDE "FILEIO.ch"
#Define BREAKLINE Chr(13)+Chr(10)
/*/{Protheus.doc} FBESTA01
Rest em ADVPL
@author FBS Consultoria
@since 11/03/2020
@version 1.0
@type function
/*/
User Function FBESTA01()
Return
/*/{Protheus.doc} CONSESTQ
Definição da estrutura do webservice
@author FBS Consultoria
@since 04/06/2019
@type class
/*/
WSRESTFUL CONSESTQ DESCRIPTION "Serviço REST para consulta de estoque"
WSDATA SEGKEY As String //String que vamos receber via URL
WSDATA PFILIAL As String //String que vamos receber via URL
WSDATA PRODUTO As String //String que vamos receber via URL
WSDATA ARMAZEM As String //String que vamos receber via URL
WSMETHOD GET DESCRIPTION "Retorna o estoque do produto informado na URL" WSSYNTAX "/CONSESTQ || /CONSESTQ/{PFILIAL}{PRODUTO}{ARMAZEM}" //Disponibilizamos um método do tipo GET
END WSRESTFUL
WSMETHOD GET WSSERVICE CONSESTQ
//--> Recuperamos o produto informado via URL
//--> Podemos fazer dessa forma ou utilizando o atributo ::aUrlParms, que é um array com os parâmetros recebidos via URL (QueryString)
Local cPFILIAL := Self:PFILIAL
Local cPRODUTO := Self:PRODUTO
Local cARMAZEM := Self:ARMAZEM
Local aArea := GetArea()
Local cJson := ""
Local cQuery := ""
Local cQueryORA := ""
Local aDados := {}
Local cRet := ""
Local cOrderBy := "SB2.B2_COD"
Local cBD := AllTrim(GetMV("MV_FBWEB08")) //AQUI PODE DEFINIR MSSSQL OU ORACLE
Local cPag := "10"
Local cPAGINA := ""
Local cFiltro := ""
If !u_FBSegApp(Self:SEGKEY)
Return
EndIf
Conout("WS CONSESTQ")
// define o tipo de retorno do método
::SetContentType("application/json")
aDados := u_FBESTA02(cPFILIAL, cPRODUTO, cARMAZEM, cOrderBy)
oObjCom := Objetos():New(aDados) //Cria um objeto da classe produtos para fazer a serialização na função FWJSONSerialize
cJson := FWJsonSerialize(oObjCom)
Conout(cJson)
// --> Envia o JSON Gerado para a aplicação Client
::SetResponse(cJson)
RestArea(aArea)
// --> Envia o JSON Gerado para a aplicação Client
::SetResponse(cRet)
//RpcClearEnv()
RestArea(aArea)
Return(.T.)
User Function FBESTA02(cPFILIAL, cPRODUTO, cARMAZEM, cOrderBy)
Local aRet := {}
Local cBD := 'MSSQL'
Default cOrderBy := "SB2.B2_COD"
Conout("FILIAL: " + cPFILIAL + " PRODUTO: " + cPRODUTO + " ARMAZEM: " + cARMAZEM)
cFiltro := ""
If ! Empty(cPFILIAL)
cFiltro += " AND SB2.B2_FILIAL = '" + cPFILIAL + "' " + BREAKLINE
EndIf
If ! Empty(cPRODUTO)
cFiltro += " AND SB2.B2_COD = '" + UPPER(cPRODUTO) + "' " + BREAKLINE
EndIf
If ! Empty(cARMAZEM)
cFiltro += " AND SB2.B2_LOCAL = '" + cARMAZEM + "' " + BREAKLINE
EndIf
cQuery := "SELECT B2_QATU " + BREAKLINE
cQuery += "FROM " + RetSQLName("SB2") + " as SB2 WITH(NOLOCK) " + BREAKLINE
cQuery += "WHERE SB2.D_E_L_E_T_ = '' " + BREAKLINE
cQuery += cFiltro
cQuery += "ORDER BY " + cOrderBy
If cBD == 'ORACLE'
cQueryORA := " SELECT ROWNUM + (" + cPag + " * (PAGINA - 1)) AS LINNUM " + BREAKLINE
cQueryORA += " ,B.* " + BREAKLINE
cQueryORA += " FROM (SELECT COUNT(*) OVER() AS TOTALREG " + BREAKLINE
cQueryORA += " ,TRUNC((ROW_NUMBER() OVER(" + cOrderBy + ") - 1) / " + cPag + ") + 1 AS PAGINA " + BREAKLINE
cQueryORA += " ,TMP.* " + BREAKLINE
cQueryORA += " FROM ( " + BREAKLINE
cQueryORA += cQuery
cQueryORA += ") TMP " + BREAKLINE
cQueryORA += ") B " + BREAKLINE
If !Empty(cPAGINA)
cQueryORA += " WHERE PAGINA = " + cPAGINA + " " + BREAKLINE
EndIf
cQuery := cQueryORA
EndIf
Conout("CONSESTQ cQuery: " + cQuery)
If Select("QRY_AUX") > 0
QRY_AUX->(dbCloseArea())
EndIf
//Executando consulta e setando o total da régua
TCQuery cQuery New Alias "QRY_AUX"
Count to nTotal
QRY_AUX->(DbGoTop())
While ! QRY_AUX->(Eof())
aAdd(aRet, { QRY_AUX->B2_QATU,;
})
QRY_AUX->(dbSkip())
EndDo
QRY_AUX->(dbCloseArea())
Return aRet
##