Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

...

Classe de criação do adapter
Bloco de código
themeRDark
#include 'totvs.ch'
#include 'parmtype.ch'
//-------------------------------------------------------------------
/*/{Protheus.doc} PrdAdapter
Classe Adapter para o serviço
@author  Anderson Toledo
/*/
//-------------------------------------------------------------------
CLASS PrdAdapter FROM FWAdapterBaseV2
	METHOD New()
	METHOD GetListProd()
EndClass

Method New( cVerb ) CLASS PrdAdapter
	_Super:New( cVerb, .T. )
return

Method GetListProd( ) CLASS PrdAdapter
	Local aArea 	AS ARRAY
	Local cWhere	AS CHAR
	aArea   := FwGetArea()
	//Adiciona o mapa de campos Json/ResultSet
	AddMapFields( self )
	//Informa a Query a ser utilizada pela API
	::SetQuery( GetQuery() )
	//Informa a clausula Where da Query
	cWhere := " B1_FILIAL = '"+ FWxFilial('SB1') +"' AND SB1.D_E_L_E_T_ = ' '"
	::SetWhere( cWhere )
	//Informa a ordenação padrão a ser Utilizada pela Query
	::SetOrder( "B1_COD" )
	//Executa a consulta, se retornar .T. tudo ocorreu conforme esperado
	If ::Execute() 
		// Gera o arquivo Json com o retorno da Query
		::FillGetResponse()
	EndIf
	FwrestArea(aArea)
Return

Static Function AddMapFields( oSelf )
	
	oSelf:AddMapFields( 'CODE'              , 'B1_COD'  , .T., .T., { 'B1_COD', 'C', TamSX3( 'B1_COD' )[1], 0 } )
	oSelf:AddMapFields( 'DESCRIPTION'	    , 'B1_DESC' , .T., .F., { 'B1_DESC', 'C', TamSX3( 'B1_DESC' )[1], 0 } )	
	oSelf:AddMapFields( 'GROUP'		        , 'B1_GRUPO', .T., .F., { 'B1_GRUPO', 'C', TamSX3( 'B1_GRUPO' )[1], 0 } )
	oSelf:AddMapFields( 'GROUPDESCRIPTION'	, 'BM_DESC' , .T., .F., { 'BM_DESC', 'C', TamSX3( 'BM_DESC' )[1], 0 } )
Return 

Static Function GetQuery()
	Local cQuery AS CHARACTER
	
	//Obtem a ordem informada na requisição, a query exterior SEMPRE deve ter o id #QueryFields# ao invés dos campos fixos
	//necessáriamente não precisa ser uma subquery, desde que não contenha agregadores no retorno ( SUM, MAX... )
	//o id #QueryWhere# é onde será inserido o clausula Where informado no método SetWhere()
	cQuery := " SELECT #QueryFields#"
    cQuery +=   " FROM " + RetSqlName( 'SB1' ) + " SB1 "
    cQuery +=   " LEFT JOIN " + RetSqlName( 'SBM' ) + " SBM"
	cQuery +=       " ON B1_GRUPO = BM_GRUPO"
	cQuery +=           " AND BM_FILIAL = '"+ FWxFilial( 'SBM' ) +"'"
	cQuery +=           " AND SBM.D_E_L_E_T_ = ' '"
    cQuery += " WHERE #QueryWhere#"	
Return cQuery

...

Bloco de código
#include "totvs.ch"
#include "restful.ch"
//-------------------------------------------------------------------
/*/{Protheus.doc} products
Declaração do ws products
@author Anderson Toledo
/*/
//-------------------------------------------------------------------
WSRESTFUL products DESCRIPTION 'endpoint products API' FORMAT "application/json,text/html"
    WSDATA Page     AS INTEGER OPTIONAL
    WSDATA PageSize AS INTEGER OPTIONAL
    WSDATA Order    AS CHARACTER OPTIONAL
    WSDATA Fields   AS CHARACTER OPTIONAL

 	WSMETHOD GET ProdList;
	    DESCRIPTION "Retorna uma lista de produtos";
	    WSSYNTAX "/api/v1/products" ;
        PATH "/api/v1/products" ;
	    PRODUCES APPLICATION_JSON
 	
END WSRESTFUL

WSMETHOD GET ProdList QUERYPARAM Page WSREST products
Return getPrdList(self)

Static Function getPrdList( oWS )
   Local lRet  as logical
   Local oProd as object
   DEFAULT oWS:Page      := 1  
   DEFAULT oWS:PageSize  := 10
   DEFAULT oWS:Fields    := ""
   lRet        := .T.
   //PrdAdapter será nossa classe que implementa fornecer os dados para o WS
   // O primeiro parametro indica que iremos tratar o método GET
   oProd := PrdAdapter():new( 'GET' )  
   //o método setPage indica qual página deveremos retornar
   //ex.: nossa consulta tem como resultado 100 produtos, e retornamos sempre uma listagem de 10 itens por página.
   // a página 1 retorna os itens de 1 a 10
   // a página 2 retorna os itens de 11 a 20
   // e assim até chegar ao final de nossa listagem de 100 produtos 
   oProd:setPage(oWS:Page)
   // setPageSize indica que nossa página terá no máximo 10 itens
   oProd:setPageSize(oWS:PageSize)
   // SetOrderQuery indica a ordem definida por querystring
   oProd:SetOrderQuery(oWS:Order)
   // setUrlFilter indica o filtro querystring recebido (pode se utilizar um filtro oData)
   oProd:SetUrlFilter(oWS:aQueryString )
   // SetFields indica os campos que serão retornados via querystring
   oProd:SetFields( oWS:Fields )   
   // Esse método irá processar as informações
   oProd:GetListProd()
   //Se tudo ocorreu bem, retorna os dados via Json
   If oProd:lOk
       oWS:SetResponse(oProd:getJSONResponse())
   Else
   //Ou retorna o erro encontrado durante o processamento
       SetRestFault(oProd:GetCode(),oProd:GetMessage())
       lRet := .F.
   EndIf
   //faz a desalocação de objetos e arrays utilizados
   oProd:DeActivate()
   oProd := nil   
Return lRet

A partir do exemplo acima é possível realizar filtros no retorno do GET, abaixo exemplos utilizando paginação e o padrão oData.

Obs. Endereço e conteúdo da comparação deve ser ajustado de acordo com o ambiente utilizado.
Filtro utilizando paginação
Exemplo com utilização de r_e_c_n_o_ e substr, a utilização de funções SQL pode exigir a necessidade de fazer uma subquery:
Bloco de código
languagejs
themeMidnight
titleAdapter - SED
#include "protheus.ch"

//-------------------------------------------------------------------
/*/{Protheus.doc} NaturezasAdapter
Classe Adapter para o serviço de Naturezas SED

@author Daniel Mendes
@version 1.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
class NaturezasAdapter from FWAdapterBaseV2
    private data lAllFields as logical

    public method new()
    public method setAllFields()
    public method getListNaturezas()
endclass

//-------------------------------------------------------------------
/*/{Protheus.doc} new
Construtor da classe

@return self, object, instância da classe

@type method
@author Daniel Mendes
@version 1.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
method new( cVerb as character) as object class NaturezasAdapter
_Super:New(cVerb, .T.)
self:lAllFields := .F.
return

//-------------------------------------------------------------------
/*/{Protheus.doc} setAllFields
Efetua o set para retornar os campos de função e recno

@return lAllFields, logical, indica o retorno dos campos de função SQL e recno

@type method
@author Daniel Mendes
@version 1.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
method setAllFields(lAllFields as logical) class NaturezasAdapter
self:lAllFields := lAllFields
return

//-------------------------------------------------------------------
/*/{Protheus.doc} getListNaturezas
Executa o adapter

@type method
@author Daniel Mendes
@version 1.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
method getListNaturezas() class NaturezasAdapter
local cWhere as character

AddMapFields(self, self:lAllFields)
::SetQuery(GetQuery(self:lAllFields))

cWhere := " SED.ED_FILIAL = '"+ FWxFilial("SED") +"' AND SED.D_E_L_E_T_ = ' '"

::SetWhere( cWhere )
::SetOrder( "ED_CODIGO" )

::setIsCaseSensitive(.T.) //Mantém o case no JSON de resposta

if ::Execute()
    ::FillGetResponse()
endif

return

//-------------------------------------------------------------------
/*/{Protheus.doc} addMapFields
Adiciona os campos do adapter

@param oSelf, object, objeto do adapter
@param lAllFields, logical, indica o retorno dos campos de função SQL e recno

@type function
@author Daniel Mendes
@version 1.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
static function addMapFields(oSelf as object, lAllFields as logical)
oSelf:AddMapFields("code"              , "ED_CODIGO"  , .T., .T., { "ED_CODIGO", "C", TamSX3("ED_CODIGO")[1], 0 } )
oSelf:AddMapFields("description"       , "ED_DESCRIC" , .T., .F., { "ED_DESCRIC", "C", TamSX3("ED_DESCRIC")[1], 0 } )

if lAllFields
    oSelf:AddMapFields("recnoNickname"     , "RECNO_NICK"  , .T., .F., { "RECNO_NICK", "N", 16, 0 }) //Com "apelido" no campo
    oSelf:AddMapFields("recno"             , "RECNO"       , .T., .F., { "RECNO", "N", 16, 0 }, "R_E_C_N_O_") //Com campo especial
    oSelf:AddMapFields("subStrDescription" , "SUBSTR_DESC" , .T., .F., { "SUBSTR_DESC", "C", 5, 0 } ) //Com função SQL
endif

return

//-------------------------------------------------------------------
/*/{Protheus.doc} getQuery
Retorna a query do Adapter

@param lAllFields, logical, indica o retorno dos campos de função SQL e recno

@return cQuery, character, Query da SED

@type function
@author Daniel Mendes
@version 1.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
static function getQuery(lAllFields as logical) as character
local cQuery as character
local cTable as character

cTable := RetSqlName("SED")

cQuery := " SELECT #QueryFields#"
cQuery += " FROM "

if lAllFields
    cQuery += " ( SELECT ED_FILIAL, ED_CODIGO, ED_DESCRIC, R_E_C_N_O_ RECNO_NICK, "
    cQuery += " SUBSTR(ED_DESCRIC, 1 , 5) SUBSTR_DESC, R_E_C_N_O_, D_E_L_E_T_ "
    cQuery += " FROM " + cTable + " ) "
else
    cQuery += cTable
endif

cQuery += " SED "
cQuery += " WHERE #QueryWhere#"

return cQuery

Bloco de código
languagejs
themeMidnight
titleServiço - SED
#include "protheus.ch"
#include "restful.ch"

//-------------------------------------------------------------------
/*/{Protheus.doc} naturezas
Serviço REST de Naturezas com Adapter

@author Daniel Mendes
@version 1.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
wsrestful naturezas description 'endpoint naturezas API' format "application/json,text/html"
    wsdata Page     as integer optional
    wsdata PageSize as integer optional
    wsdata Order    as character optional
    wsdata Fields   as character optional
 
    wsmethod get NatV1List;
        description "Retorna uma lista de naturezas";
        wssyntax "/api/v1/naturezas" ;
        path "/api/v1/naturezas" ;
        produces APPLICATION_JSON

    wsmethod get NatV2List;
        description "Retorna uma lista de naturezas";
        wssyntax "/api/v2/naturezas" ;
        path "/api/v2/naturezas" ;
        produces APPLICATION_JSON
     
end wsrestful

//-------------------------------------------------------------------
/*/{Protheus.doc} NatV1List
Verbo GET da API de Naturezas

@return logical, indica sucesso na requisição

@type method
@author Daniel Mendes
@version 1.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
wsmethod get NatV1List queryparam Page wsrest naturezas
return getNaturezasList(self, .F.)

//-------------------------------------------------------------------
/*/{Protheus.doc} NatV2List
Verbo GET da API de Naturezas

@return logical, indica sucesso na requisição

@type method
@author Daniel Mendes
@version 2.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
wsmethod get NatV2List queryparam Page wsrest naturezas
return getNaturezasList(self, .T.)

//-------------------------------------------------------------------
/*/{Protheus.doc} getNaturezasList
Executa o adapter de Naturezas para o verbo GET

@param oWS, object, objeto REST
@param lAllFields, logical, indica o retorno dos campos de função SQL e recno

@return lRet, logical, indica sucesso na requisição

@type function
@author Daniel Mendes
@version 1.0
@since 07/09/2023
/*/
//-------------------------------------------------------------------
static function getNaturezasList(oWS as object, lAllFields as logical)
local lRet  as logical
local oNatSED as object

default oWS:Page      := 1 
default oWS:PageSize  := 10
default oWS:Fields    := ""

oNatSED := NaturezasAdapter():new("GET")

oNatSED:setAllFields(lAllFields)
oNatSED:setPage(oWS:Page)
oNatSED:setPageSize(oWS:PageSize)
oNatSED:setOrderQuery(oWS:Order)
oNatSED:setUrlFilter(oWS:aQueryString)
oNatSED:setFields(oWS:Fields)
oNatSED:getListNaturezas()

lRet := oNatSED:IsOk()

if lRet
    oWS:SetResponse(oNatSED:getJSONResponse())
else
    SetRestFault(oNatSED:GetCode(),oNatSED:GetMessage())
EndIf

oNatSED:DeActivate()
FreeObj(oNatSED)
oNatSED := nil

return lRet

A partir do exemplo acima é possível realizar filtros no retorno do GET, abaixo exemplos utilizando paginação e o padrão oData.

Obs. Endereço e conteúdo da comparação deve ser ajustado de acordo com o ambiente utilizado.
Filtro utilizando paginação
Bloco de código
http:/
Bloco de código
http://localhost:8080/teste/rest/api/v1/products?pagesize=1&page=3

...

Aviso
titleCampos memo - SYP

A classe não dá suporte ao campos memo que utilizam da SYP.

Nota
titleChangeQuery

A classe FWAdapterBaseV2 não faz uso da ChangeQuery, logo a utilização de concatenação e/ou funções SQL devem ser evitadas ou tratadas quando necessário.