Consumo api externa

Bom dia!
Estou com o erro de retorno:
“{“code”:“InvalidDataAccessResourceUsageException”,“message”:“could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet”,“detailedMessage”:“could not extract ResultSet”}”

Ao consumir a api, via POSTMAN, o retorno ocorre corretamente, mas, em execução via Protheus só retorna o erro acima.

Anexo fontes utilizados.

User Function TesteGet()

Local oClsToken :=  clsTokenTotvsRac():New(.T.)    As  Object
Local oClsIDFilial  :=  clsIDsWMSSaaS():New()   As  object
Local cToken    :=  oClsToken:getToken()        As  Character

aRet            :=  oClsIDFilial:getIDFilial(cToken)

Return

#INCLUDE ‘TCBROWSE.CH’
#INCLUDE ‘PROTHEUS.CH’
#INCLUDE ‘RWMAKE.CH’
#INCLUDE ‘TBICONN.CH’
#INCLUDE ‘TOTVS.CH’
#INCLUDE ‘TOPCONN.CH’
#INCLUDE ‘FWMVCDEF.CH’
#INCLUDE ‘tlpp-core.th’
#INCLUDE ‘tlpp-object.th’

//{Protheus.doc} clsTokenTotvsRac
Classe utilizada para retornar o token de acesso para utilização no WMS SaaS
Conecta no Totvs RAC, onde, deve-se ter obrigatoriamente um ClientID e ClientSecret para acesso na plataforma
@type class
@author willian
@since 25/09/2025
/
/
Class clsTokenTotvsRac

Private Data cUrl           as character

Private Data cTenant		as Character
Private Data cClientId      as Character
Private Data cClientSecret  as Character

Public Method new(lTest)	Constructor

Public Method getToken()

EndClass

//{Protheus.doc} clsTokenTotvsRac::new
Method construtor da classe.
@type method
@author willian
@since 25/09/2025
@return variant, self
/
/
Method new(lTest) class clsTokenTotvsRac

Default lTest		:=	.F.

self:cTenant        :=  IIF(!lTest,AllTrim(GetNewPar("SC_APPTENA","scalon")),"treinamento-scala")
self:cClientId      :=  IIF(!lTest,AllTrim(GetNewPar("SC_APPCLID","24b60912bb674467ae77f43b0bb1dbbc")),"7b77cb643c6b42bea9e372f999f8ce7b")
self:cClientSecret	:=	IIF(!lTest,AllTrim(GetNewPar("SC_APPCLSC","6038db32ea70454b9154eb2b01aab0a9")),"d70622c684ec4172958584278d7d9c88")

self:cUrl       	:=	"https://"+self:cTenant+".rac.totvs.app/"

Return(self)

//{Protheus.doc} clsLoginAPI::getToken
Metodo responsavel pela conexao e retorno do token de acesso atraves do Totvs Rac
@type method
@author lucas.lima
@since 06/10/2023
@return character, cRet, token retornado pelo Totvs Rac
/
/
Method getToken() class clsTokenTotvsRac

Local xRet      
Local cRet      as character
Local cPostPar  as character
Local aHeader	:= {}  as array
Local oJson     as object
Local oRest     as object

Aadd(aHeader,"Content-Type: application/x-www-form-urlencoded" )

oJson := JsonObject():New()

cPostPar := "grant_type=client_credentials"
cPostPar += "&client_id=" + self:cClientId
cPostPar += "&client_secret=" + Escape(self:cClientSecret)

oRest := FwRest():New(self:cUrl)
oRest:setPath("totvs.rac/connect/token")
oRest:setPostParams(cPostPar)

If oRest:Post(aHeader)
	xRet := oJson:FromJson(oRest:cResult)

	If ValType(xRet) == "C"
		cRet    := "Não foi possível retonar o TOKEN Totvs RAC." + xRet
	Else
		cRet    := oJson["access_token"]
	EndIf
Else
	cRet := "Erro em Post."
EndIf

Return cRet

#INCLUDE ‘TCBROWSE.CH’
#INCLUDE ‘PROTHEUS.CH’
#INCLUDE ‘RWMAKE.CH’
#INCLUDE ‘TBICONN.CH’
#INCLUDE ‘TOTVS.CH’
#INCLUDE ‘TOPCONN.CH’
#INCLUDE ‘FWMVCDEF.CH’
#INCLUDE ‘tlpp-core.th’
#INCLUDE ‘tlpp-object.th’
//{Protheus.doc} clsIDFilialWms
Classe responsavel pelas operacoes entre ERP e WMS SaaS
@type Class
@author Willian
@since 09/10/2025
@version 1.0.0
/
/
Class clsIDsWMSSaaS

Private Data cUrl       as character

Public Method New()   Constructor

Public Method getIDFilial(cToken,cFil)
Public Method getIDCaracte(cToken)
Public Method getIdProduto(cToken,cProd)
Public Method postIdEstoque(cToken,cIDOrgWMS,cIDProduto,cIDCaracteristica)
Public Method getIdTpEstoque(cToken,nIdOrgWMS)
Public Method postAltEstoque(cToken,cIDEstoque,cTpEstoque)

EndClass

//{Protheus.doc} New
Metodo de instanciamento da classe
@type method
@author Willian
@since 09/10/2025
@version 1.0.0
@return (self), return_type, return_description
/
/
Method New() Class clsIDsWMSSaaS

self:cUrl   :=  GetNewPar("SC_WMSSaaS","https://supply.logistica.totvs.app","")

Return (self)

//{Protheus.doc} getIDFilialWMS
Metodo responsavel pelo retorno do ID da organizacao dentro do WMS SaaS
@type method
@author Willian
@since 09/10/2025
@version 1.0.0
@param cFil, character, código da filial
@return aDados, array, Id’s organizacao no WMS SaaS
/
/
Method getIDFilial(cToken,cFil) Class clsIDsWMSSaaS

Local xRet      
Local cRet      :=  ""      as  character
Local cGetPar   :=  ""      as  character
Local cAPIPath  :=  ""      as  character
Local aHeader	:=  {}      as  array
Local aDados    :=  {}      as  array
Local oJson     :=  nil     as  object
Local oRest     :=  nil     as  object

cAPIPath    :=  "/wms/query/api/v1/integracao/configOrganizacao"

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

oJson := JsonObject():New()

cGetPar :=  "situacao=ATIVO"
If !empty(cFil)
    cGetPar += "&filialErp=01," + cFil + "00"
EndIf

oRest := FwRest():New(self:cUrl)
oRest:setPath(cAPIPath)
oRest:setGetParams(EncodeUTF8(cGetPar))

If oRest:Get(aHeader)
	xRet := oJson:FromJson(oRest:cResult)

	If ValType(xRet) == "C"
		cRet    := "Não foi possível retonar o ID da filial no WMS SaaS." + xRet
	Else
        //Oganizacao_ID (numerico)
        //Unidade ID (hash)
        //ID (hash)
        aAdd(aDados,oJson["items"][1]["organizacao"]["id"])
        aAdd(aDados,oJson["items"][1]["organizacao"]["unidadeId"])
        aAdd(aDados,oJson["items"][1]["id"])
	EndIf
Else
    xRet := oJson:FromJson(oRest:cResult)
	cRet := "Erro Get ID Unidade/Filial WMS SaaS. " + "Erro: " + xRet
    aAdd(aDados,cRet)
EndIf

Return aDados

Olá,

O Postman coloca diversos headers na requisição mesmo que você não configure, isso acaba fazendo com que sua requisição via ADVPL e via Postman não sejam a mesma, por mais que sejam muito parecidas.

Dê uma conferida no que o Postman está fazendo durante sua requisição, dê uma conferida nos headers, podendo ser Content-Length, Host, Accept-Encoding, Connection etc… Por experiência, o Content-Length costuma ser o vilão.

Esse cenário é bem comum, vive acontecendo e sempre foi possível resolver enviando os dados corretos para API externa via ADVPL.

É bom lembrar, o Postman é uma ferramenta facilitadora para efetuar requisições, ele tenta fazer o trabalho por você, tornar mais fácil, porém quando você está fazendo a requisição por conta, o cenário muda e você precisa descobrir cada detalhe que a API externa espera, infelizmente muitas APIs geram erros e não informam o motivo e isso dificulta a análise.

1 curtida

Muito obrigado pela dica, era isso mesmo. Ajustei as requisições com o Header de acordo com o Postman e funcionou perfeitamente.