Método POST API REST em ADVPL

Bom dia. Não sei o que estou fazendo de errado estou aprendendo a codificar em ADVPL a utilização de APIs via REST. Inclui uma nova API e coloquei dois métodos um GET e um POST o método GET consegui fazer sem problemas em ADVPL. Porém o método POST esta aparecendo a mensagem no console do REST que não conseguiu encontrar o método da erro 404 - Not Found. Alguem poderia me ajudar com relação a isso? Segue arquivo desenvolvido. User Funcion EREST_01 é a criação do API User Function EREST_02 é a utilização do método GET User Function EREST_03 é a utilização do método POST

:warning: Atenção: Esta publicação foi transferida automaticamente do fórum antigo, mas os anexos não foram incluídos.

Rafael, por favor, edite a pergunta e anexe o código fonte.

Opa. Desculpe. Agora esta ok

Agora Esta OK Daniel

Rafael,

Existem diversos problemas em seu exemplo, tais como:

  • Declaração de classe produtos no fonte, mas sem utilização.
    • Utilização da função FWJsonDeserialize, essa função está depreciada.
    • Utilização da função FWMVCRotAuto já tendo o modelo instanciado e pronto para ser trabalhado.
    • Criação do método POST esperando receber informações na URL: {Fields}, mas isso é uma inserção, ainda não existe nada pra ser acessado.
    • Abrir o ambiente dentro do método POST com o PREPARE ENVIRONMENT.
    • Na função getJson, a criação do json está sendo feita com um bloco de código: {|| JsonObject():New()}
    • Você pegou a área corrente antes de manipular a SB1 e restaurou a mesma, correto, porém você não fez o mesmo para a área da SB1, que é exatamente a tabela que você manipulou.
    • Includes sem utilização, como o tbiconn.ch.

Veja aqui um exemplo com as correções dos erro citados acima:



#include "protheus.ch"
#include "fwmvcdef.ch"
#include "restful.ch"

//-------------------------------------------------------------------
/*{Protheus.doc} Produtos1
API para inserção e consulta de produtos (SB1)

@author Daniel Mendes
@since 06/07/2020
@version 1.0
*/
//-------------------------------------------------------------------
WSRESTFUL Produtos1 DESCRIPTION "Serviço REST para manipulação de Produtos"

    WSDATA CodProduto As String

    WSMETHOD GET DESCRIPTION "Retorna o produto informado na URL" WSSYNTAX "/PRODUTOS1"
    WSMETHOD POST DESCRIPTION "Retorna o produto informado na URL" WSSYNTAX "/PRODUTOS1" PATH "/PRODUTOS1" PRODUCES APPLICATION_JSON

END WSRESTFUL

//-------------------------------------------------------------------
/*{Protheus.doc} GET
Retorna um json com os dados do produto consultado

@author Daniel Mendes
@since 06/07/2020
@version 1.0
*/
//-------------------------------------------------------------------
WSMETHOD GET WSRECEIVE CodProduto WSSERVICE Produtos1
local aAreaSB1 as array
Local aObjProd as array
Local aArea as array
Local cCodProd as char
Local cStatus as char
Local cJson as char
Local jObjProd

cCodProd := Self:CodProduto
aArea := GetArea()
aAreaSB1 := SB1->( GetArea() )

::SetContentType("application/json")

DbSelectArea("SB1")
SB1->( DbSetOrder(1) )

if SB1->( DbSeek( xFilial("SB1") + PadR(cCodProd,15) ) )
    aObjProd := {}
    cStatus := Iif( SB1->B1_MSBLQL == "1", "Sim", "Nao" )

    aAdd( aObjProd,  JsonObject():New() )

    aObjProd[1]["Produto"        ] := cCodProd 
    aObjProd[1]["Descricao"        ] := SB1->B1_DESC
    aObjProd[1]["Unidade Medida"] := SB1->B1_UM
    aObjProd[1]["Status"        ] := cStatus

    jObjProd :=  JsonObject():New()
    jObjProd["PRODUTOS1"] := aObjProd

    cJson := jObjProd:toJson()
    ::setResponse(cJson)
else
    setRestFault(404)
endIf

RestArea(aAreaSB1)
RestArea(aArea)

return .T.

//-------------------------------------------------------------------
/*{Protheus.doc} POST
Efetua a inserção de um produto com base no JSON recebido

@author Daniel Mendes
@since 06/07/2020
@version 1.0
*/
//-------------------------------------------------------------------
WSMETHOD POST WSSERVICE Produtos1
local jProduto
local cError as char
local cJson as char
local cAlias as char
local lOk as logical
local aAreaSB1 as array

Self:SetContentType("application/json")

jProduto := JsonObject():New()
cError := jProduto:fromJson( self:getContent() )
lOk := .F.

if Empty(cError)]
    cAlias := Alias()
    aAreaSB1 := SB1->( GetArea() )

    if !SB1->( DbSeek( xFilial("SB1") + jProduto["CODPRODUTO"]) )
        oModel := FwLoadModel("MATA010")

        oModel:setOperation(MODEL_OPERATION_INSERT)
        oModel:Activate()

        oModel:setValue("SB1MASTER", "B1_COD", jProduto["CODPRODUTO"])
        oModel:setValue("SB1MASTER", "B1_DESC", jProduto["PRODDESC"])
        oModel:setValue("SB1MASTER", "B1_GRUPO", jProduto["CODGRUPO"])
        oModel:setValue("SB1MASTER", "B1_TIPO", jProduto["PRODTIPO"])
        oModel:setValue("SB1MASTER", "B1_UM", jProduto["PRODUM"])
        oModel:setValue("SB1MASTER", "B1_LOCPAD", jProduto["PRODLOCPAD"])
        oModel:setValue("SB1MASTER", "B1_ORIGEM", jProduto["PRODORIGEM"])

        if oModel:VldData()
            lOk := oModel:CommitData()

            cJson := '{"CODPRODUTO":"' + SB1->B1_COD + '"';
                    + ',"msg":"'  + "Sucesso"          + '"';
                    +'}'

            ::SetResponse(cJson)
        else
            ConErr(oModel:GetErrorMessage()[MODEL_MSGERR_MESSAGE])
            SetRestFault(400)
        endif

        oModel:Destroy()
        FreeObj(oModel)
    else
        SetRestFault(400, "Produto já cadastrado: " + SB1->B1_COD)
    endif

    RestAlias(aAreaSB1)

    if !Empty(cAlias)
        DBSelectArea(cAlias)
    endif
else
    ConErr(cError)
    setRestFault(400)
endif

return lOk

//-------------------------------------------------------------------
/*{Protheus.doc} EREST_02
Função para testes do método GET da API Produtos1

@author Daniel Mendes
@since 06/07/2020
@version 1.0
*/
//-------------------------------------------------------------------
user function EREST_02()
local oRestClient as object
local aHeader as array

oRestClient := FWRest():New("http://10.21.1.24:8093")
aHeader := {"CODPRODUTO:300001"}

oRestClient:setPath("/resty/PRODUTOS1")

if oRestClient:Get(aHeader)
   ConOut("GET", oRestClient:GetResult())
else
   ConOut("GET", oRestClient:GetLastError())
endif

FreeObj(oRestClient)

return

//-------------------------------------------------------------------
/*{Protheus.doc} EREST_03
Função para testes do método POST da API Produtos1

@author Daniel Mendes
@since 06/07/2020
@version 1.0
*/
//-------------------------------------------------------------------
user function EREST_03()
Local aHeader as array
Local cResource as char
Local cServer as char
Local cPort as char
Local cURI as char
Local oRestClient as object

aHeader := {} 
cResource := "/PRODUTOS1" 
cServer := "10.21.1.24" // URL (IP) DO SERVIDOR
cPort := "8093" // PORTA DO SERVIÇO REST
cURI := "http://" + cServer + ":" + cPort + "/resty" // URI DO SERVIÇO REST
oRestClient := FwRest():New(cURI)

AAdd(aHeader, "Content-Type: application/json; charset=UTF-8")
AAdd(aHeader, "Accept: application/json")
AAdd(aHeader, "User-Agent: Chrome/65.0 (compatible; Protheus " + GetBuild() + ")")

oRestClient:setPath(cResource)
oRestClient:SetPostParams(getJson())

if oRestClient:Post(aHeader)
   ConOut("POST", oRestClient:GetResult())
else
   ConOut("POST", oRestClient:GetLastError())
endIf

FreeObj(oRestClient)

return

//-------------------------------------------------------------------
/*{Protheus.doc} getJson
Retorna um json (Char) para o cadastro de produtos

@return Char - Json de produto

@author Daniel Mendes
@since 06/07/2020
@version 1.0
*/
//-------------------------------------------------------------------
static Function getJson()
local jJson

jJson := JsonObject():New()

jJson["CODGRUPO"] := "001"
jJson["CODPRODUTO"] := "001323"
jJson["PRODDESC"] := "TESTE PRODUTO3 API REST"
jJson["PRODTIPO"] := "PA"
jJson["PRODUM"] := "UN"
jJson["PRODLOCPAD"] := "01"
jJson["PRODORIGEM"] := "0"

return jJson:ToJson()

O que foi feito:

  • Tipagem das variáveis.
    • Correção da URL do método POST.
    • Remoção da abertura do ambiente no meio do método.
    • Remoção da utilização da função FWMVCRotAuto, agora o modelo é ativo e seus valores são inseridos diretamente no mesmo, isso também gera ganho de performance.
    • Remoção da utilização da função FWJsonDeserialize, agora sempre é utilizada a JsonObject, que retorna um JSON e não um objeto.

Espero ter ajudado, desculpe por reescrever grande parte das coisas, mas acho que ficou mais fácil para exemplificar.

Obrigado. Ajudou bastante. Valeu mesmo. Os exemplo que peguei na internet devem estar desatualizados mesmo, por isso esta cheio de falhas e atrelado ai isso estou aprendendo a trabalhar com API e REST ai ate entender como funciona vou apanhar muito ainda.