Versões comparadas
Chave
- Esta linha foi adicionada.
- Esta linha foi removida.
- A formatação mudou.
Objetivo
Possibilitar acesso aos modelos de dados do Protheus através de API RESTFul.
Pré-requisitos
- Conhecimento do MVC do Protheus
- Configurar o servidor REST do TOTVS | Application Server
Requisitos Mínimos
Para utilizar certifique-se que:
- O TOTVS | AppServer é superior ou igual a build 7.00.121227P - Aug 12 2013
* Para atualização do ambiente, consulte nossa Central de Download no endereço: http://www.totvs.com.br/suporte
Como utilizar
Os modelos de dados devem ser publicados para serem acessíveis através da API, para isso deve-se utilizar o seguinte comando:
Informações |
---|
PUBLISH MODEL REST NAME <nome> source <fonte> RESOURCE OBJECT <objeto> |
Obs: Cada modelo deverá ser publicado utilizando esse comando. Não é necessário estar no mesmo fonte do modelo de dados.
NAME = Nome da API que representará o modelo de dados.
SOURCE = Fonte aonde está o modelo de dados (função modeldef), caso esse comando não for informado, será acatado o fonte atual. (Não é obrigatório)
RESOURCE OBJECT = Classe que deverá herdar da FwRestModel. (Não é obrigatório)
Com este comando os modelos de dados serão acessíveis através do seguinte endereço: <protocol>://<server>:<port>/fwmodel/<name of published model>/<PK>
Exemplo: http://localhost:8084/fwmodel/products
Parametros
<Name of published model> = Nome o modelo informado no comando
<PK> = Valor da chave primaria do alias do modelo em encodado em base64 (Opcional)
Classe FWRestModel (link: FWRestModelObject.prx)
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
#INCLUDE "TOTVS.CH" #INCLUDE "FWMVCDEF.CH" // Função Dummy Function __FwRestModel__() Return //------------------------------------------------------------------- /*/{Protheus.doc} FwRestModel Classe base para controlar o acesso aos registros relacionados ao modelo de dados. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Class FwRestModel Data cName Data cAlias Data oModel Data lXml Data lActivate Data cFilter Data cOldFilter Method Activate() Method DeActivate() Method OnError() Method SetModel() Method ClearModel() Method SetName() Method GetName() Method SetAsXml() Method SetAsJson() Method StartGetFormat() Method EscapeGetFormat() Method EndGetFormat() Method SetAlias() Method HasAlias() Method Seek() Method Skip() Method Total() Method GetData() Method SaveData() Method DelData() Method SetFilter() Method GetFilter() Method ClearFilter() Method DecodePK() Method ConvertPK() EndClass //------------------------------------------------------------------- /*/{Protheus.doc} Activate Método de ativação da classe. @return lActivate Indica que a classe foi ativada. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method Activate() Class FwRestModel self:lXml := .T. Return self:lActivate := .T. //------------------------------------------------------------------- /*/{Protheus.doc} DeActivate Método de desativação da classe. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method DeActivate() Class FwRestModel self:ClearModel() self:ClearFilter() self:lActivate := .F. Return //------------------------------------------------------------------- /*/{Protheus.doc} OnError Método que será executado quando algum erro ocorrer no rest. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method OnError() Class FwRestModel self:DeActivate() Return //------------------------------------------------------------------- /*/{Protheus.doc} SetModel Método para setar o modelo de dados que será utilizado. E força a configuração do alias a ser utilizado. @param oModel Objeto do modelo de dados @return oModel Objeto do modelo de dados setado. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method SetModel(oModel) Class FwRestModel self:oModel := oModel self:SetAlias() Return oModel //------------------------------------------------------------------- /*/{Protheus.doc} ClearModel Método para efetuar o desroy do modelo de dados. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method ClearModel() Class FwRestModel If self:oModel != Nil self:oModel:Destroy() self:oModel := Nil EndIf Return //------------------------------------------------------------------- /*/{Protheus.doc} SetName Método para setar o nome do rest do modelo de dados. @return cName Nome do rest do modelo de dados. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method SetName(cName) Class FwRestModel Return self:cName := cName //------------------------------------------------------------------- /*/{Protheus.doc} GetName Método para retornar o nome do rest do modelo de dados. @return cName Nome do rest do modelo de dados. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method GetName() Class FwRestModel Return self:cName //------------------------------------------------------------------- /*/{Protheus.doc} SetAsXml Método para setar o retorno do rest como XML. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method SetAsXml() Class FwRestModel self:lXml := .T. Return //------------------------------------------------------------------- /*/{Protheus.doc} SetAsJson Método para setar o retorno do rest como JSON. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method SetAsJson() Class FwRestModel self:lXml := .F. Return //------------------------------------------------------------------- /*/{Protheus.doc} StartGetFormat Método retornar o conteúdo inicial do dado de retorno. @param nTotal Quantidade total de registros do alias que podem ser retornados. @param nCount Quantidade de registros a serem retornados. @param nStartIndex Index inicial do registro que será retornado. @return cRet Conteúdo inicial @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method StartGetFormat(nTotal, nCount, nStartIndex) Class FwRestModel Local cRet := "" If self:lXml cRet += '<?xml version="1.0" encoding="UTF-8"?>' cRet += '<result>' cRet += i18n('<total>#1</total><count>#2</count><startindex>#3</startindex>', {nTotal, nCount, nStartIndex}) cRet += '<resources>' Else cRet += i18n('{"total":#1,"count":#2,"startindex":#3,"resources":[', {nTotal, nCount, nStartIndex}) EndIf Return cRet //------------------------------------------------------------------- /*/{Protheus.doc} EscapeGetFormat Método retornar o caracter a ser inserido entre os registros a serem retornados. @return cRet Caracter de escape. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method EscapeGetFormat() Class FwRestModel Local cRet := "" If !self:lXml cRet := "," EndIf Return cRet //------------------------------------------------------------------- /*/{Protheus.doc} EndGetFormat Método retornar o conteúdo final do dado de retorno. @return cRet Conteúdo final @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method EndGetFormat() Class FwRestModel Local cRet := "" If self:lXml cRet := "</resources>" cRet += "</result>" Else cRet := "]}" EndIf Return cRet //------------------------------------------------------------------- /*/{Protheus.doc} SetAlias Método responsável por setar o alias a ser utilizado. Se o mesmo não for informado, será utilizado o alias do field principal do modelo de dados. @return lRet Indica se o alias foi preenchido @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method SetAlias(cAlias) Class FwRestModel If Empty(cAlias) If !Empty(self:oModel) self:cAlias := MPGetModelAlias(self:oModel) dbSelectArea(self:cAlias) EndIf Else self:cAlias := cAlias EndIf Return !Empty(self:cAlias) //------------------------------------------------------------------- /*/{Protheus.doc} HasAlias Método responsável informar se o alias foi setado, se não força efetuar o setAlias(). @return lRet Indica se o alias foi preenchido @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method HasAlias() Class FwRestModel Local lRet := .T. If Empty(self:cAlias) self:SetAlias() lRet := !Empty(self:cAlias) EndIf Return lRet //------------------------------------------------------------------- /*/{Protheus.doc} Seek Método responsável buscar um registro em específico no alias selecionado. Se o parametro cPK não for informaodo, indica que deve-se ser posicionado no primeiro registro da tabela. @param cPK PK do registro. @return lRet Indica se foi encontrado algum registro. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method Seek(cPK) Class FwRestModel Local lRet := .F. Local nOrder If self:HasAlias() If Empty(cPK) (self:cAlias)->(DbGotop()) lRet := !(self:cAlias)->(Eof()) Else nOrder := MPGetBestOrder(self:cAlias, self:oModel:GetPrimaryKey(), 1) (self:cAlias)->(dbSetOrder(nOrder)) lRet := (self:cAlias)->(DbSeek(cPK)) Endif Endif Return lRet //------------------------------------------------------------------- /*/{Protheus.doc} Skip Método responsável passar para o proximo registro do alias. @return lRet Indica se o alias não chegou ao fim. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method Skip() Class FwRestModel Local lRet := .F. If self:HasAlias() (self:cAlias)->(DbSkip()) lRet := !(self:cAlias)->(Eof()) EndIf Return lRet //------------------------------------------------------------------- /*/{Protheus.doc} Total Método responsável retornar a quantidade total de regitros do alias. Contagem é feita atravez de query. @return nTotal Quantidade total de registros. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method Total() Class FwRestModel Local nTotal := 0 If self:HasAlias() nTotal := FWTblCount(self:cAlias,,.T.) EndIf Return nTotal //------------------------------------------------------------------- /*/{Protheus.doc} GetData Método responsável por retornar o registro do modelo no formato XML ou JSON. @param lFieldDetail Indica se retorna o registro com informações detalhadas @param lFieldVirtual Indica se retorna o registro com campos virtuais @param lFieldEmpty Indica se retorna o registro com campos nao obrigatorios vazios @return cRet Retorna o registro nos formatos XML ou JSON @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method GetData(lFieldDetail, lFieldVirtual, lFieldEmpty) Class FwRestModel Local cRet self:oModel:SetOperation(MODEL_OPERATION_VIEW) Self:oModel:Activate() If self:lXml cRet := Self:oModel:GetXmlData(lFieldDetail,,,lFieldVirtual,,lFieldEmpty,.F./*lDefinition*/,,.T./*lPK*/,.T./*lPKEncoded*/) Else cRet := Self:oModel:GetJsonData(lFieldDetail,,lFieldVirtual,,lFieldEmpty,.T./*lPK*/,.T./*lPKEncoded*/) EndIf Self:oModel:DeActivate() Return cRet //------------------------------------------------------------------- /*/{Protheus.doc} SaveData Método responsável por salvar o registro recebido pelo metodo PUT ou POST. Se o parametro cPK não for informado, significa que é um POST. @param cPK PK do registro. @param cData Conteúdo a ser salvo @param @cError Retorna o alguma mensagem de erro @return lRet Indica se o registro foi salvo @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method SaveData(cPK, cData, cError) Class FwRestModel local lRet := .T. Default cData := "" If Empty(cPk) self:oModel:SetOperation(MODEL_OPERATION_INSERT) Else self:oModel:SetOperation(MODEL_OPERATION_UPDATE) lRet := self:Seek(cPK) EndIf If lRet self:oModel:Activate() If self:lXml lRet := self:oModel:LoadXMLData(cData) Else lRet := self:oModel:LoadJsonData(cData) EndIf If lRet lRet := (self:oModel:VldData() .And. self:oModel:CommitData()) EndIf If !lRet cError := ErrorMessage(self:oModel:GetErrorMessage()) EndIf Self:oModel:DeActivate() Else cError := i18n("Invalid record '#1' on table #2", {cPK, self:cAlias}) EndIf Return lRet //------------------------------------------------------------------- /*/{Protheus.doc} DelData Método responsável por remover um registro. @param cPK PK do registro. @param @cError Retorna o alguma mensagem de erro @return lRet Indica se o registro foi removido @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method DelData(cPK, cError) Class FwRestModel local lRet := .F. If !Empty(cPK) If self:Seek(cPK) self:oModel:SetOperation(MODEL_OPERATION_DELETE) self:oModel:Activate() lRet := self:oModel:VldData() .And. self:oModel:CommitData() If !lRet cError := ErrorMessage(self:oModel:GetErrorMessage()) EndIf Self:oModel:DeActivate() Else cError := i18n("Invalid record '#1' on table #2", {cPK, self:cAlias}) EndIf EndIf Return lRet //------------------------------------------------------------------- /*/{Protheus.doc} SetFilter Método responsável por setar algum filtro que tenha sido informado por Query String no REST. @param cFilter Valor do filtro a ser aplicado no alias @return lRet Indica se o filtro foi aplicado corretamente @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method SetFilter(cFilter) Class FwRestModel Local lRet := .F. If !Empty(cFilter) self:cFilter := Alltrim(cFilter) If self:HasAlias() self:cOldFilter := (self:cAlias)->(dbFilter()) If !Empty(self:cOldFilter) (self:cAlias)->(dbClearFilter()) EndIf (self:cAlias)->(dbSetFilter(&('{|| '+self:cFilter+'}'), self:cFilter)) lRet := .T. EndIf EndIf Return lRet //------------------------------------------------------------------- /*/{Protheus.doc} GetFilter Método para retornar o conteúdo do filtro. @return cFilter Conteúdo do filtro @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method GetFilter() Class FwRestModel Return self:cFilter //------------------------------------------------------------------- /*/{Protheus.doc} GetFilter Método responsável pro limpar o filtro setado. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method ClearFilter() Class FwRestModel (self:cAlias)->(dbClearFilter()) If !Empty(self:cOldFilter) (self:cAlias)->(dbSetFilter(&('{|| '+AllTrim(self:cOldFilter)+'}'), self:cOldFilter)) self:cOldFilter := Nil EndIf Return //------------------------------------------------------------------- /*/{Protheus.doc} DecodePK Método para indicar se deve ser feito o decode do paramtro cPK recebido no REST @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method DecodePK() Class FwRestModel Return .T. //------------------------------------------------------------------- /*/{Protheus.doc} ConvertPK Método responsável por converter a PK. @author Felipe Bonvicini Conti @since 25/06/2015 @version P11, P12 /*/ //------------------------------------------------------------------- Method ConvertPK(cPK) Class FwRestModel If self:DecodePK() cPK := Decode64(cPK) EndIf Return cPK // ********************* FuncionsFunctions ********************* Static Function ErrorMessage(aErroMsg) Local cRet := CRLF + " --- Error on Model ---" + CRLF cRet += "Id submodel origin: [" + aErroMsg[1] + "]" + CRLF cRet += "Id field origin: [" + aErroMsg[2] + "]" + CRLF cRet += "Id submodel error: [" + aErroMsg[3] + "]" + CRLF cRet += "Id field error: [" + aErroMsg[4] + "]" + CRLF cRet += "Id error: [" + aErroMsg[5] + "]" + CRLF cRet += "Error menssage: [" + aErroMsg[6] + "]" + CRLF cRet += "Solution menssage: [" + aErroMsg[7] + "]" + CRLF cRet += "Assigned value: [" + cValToChar( aErroMsg[8] ) + "]" + CRLF cRet += "Previous value: [" + cValToChar( aErroMsg[9] ) + "]" + CRLF aErroMsg := aSize(aErroMsg, 0) Return cRet |
Utilização
Esta API segue o padrão de REST.
Por exemplo:
Para retornar a lista de registros referente ao modelo de dados deve-se efetuar um GET sem informar a <PK>.
Para inserir um registro deve-se efetuar um POST sem informar a <PK> e enviar no body o conteúdo a ser inserido.
Ao informar o parâmetro <PK> será acessado um registro em específico e assim podendo ser utilizado os métodos GET, PUT, DELETE.
QueryStrings
COUNT = Quantidade de registro que devem ser retornados
STARTINDEX = Indica a partir que qual index deverá ser retornado
FILTER = Filtro que será aplicado no método SetFilter()
FIELDDETAIL = Habilita mostrar mais informações nos campos do modelo
FIELDVIRTUAL = Habilita o retorno de campos virtuais
Exemplo de utilização
Ao publicar um modelo de dados, se o mesmo utilizar alias, basta publicá-lo.
Caso o modelo tenha sido desenvolvido utilizando array ou carga manual, deve-se criar uma classe e herda-la da FwRestModel e sobrescrever os métodos necessários para atender a sua necessidade.
Exemplo de modelo de dados com customização da classe REST:
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
#INCLUDE "TOTVS.CH" #INCLUDE "FWMVCDEF.CH" PUBLISH MODEL REST NAME Branch RESOURCE OBJECT oRestBranch Class oRestBranch From FwRestModel Data lSm0Closed Method Activate() Method DeActivate() Method Total() Method SetAlias() EndClass Method Activate() Class oRestBranch self:lSm0Closed := .F. If Select("SM0") == 0 self:lSm0Closed := .T. OpenSm0(, .F.) EndIf Return _Super:Activate() Method DeActivate() Class oRestBranch If self:lSm0Closed SM0->(dbCloseArea()) EndIf Return _Super:DeActivate() Method Total() Class oRestBranch Local nRecno := SM0->(Recno()) Local nTotal := 0 If self:Seek() While !SM0->(Eof()) nTotal++ self:Skip() End EndIf SM0->(dbGoTo(nRecno)) Return nTotal Method SetAlias() Class oRestBranch self:cAlias := "SM0" Return .T. // MODELO DE DADOS Static Function Modeldef() Local oStruSM0 := DefStrModel() oModel := FWFormModel():New( 'MYFILIAL', {|| }, {|| }, {|| }, {|| } ) oModel:AddFields( 'SM0MASTER', , oStruSM0, {|| }, {|| },{|oM| MyLoad() }) oModel:SetDescription( "Empresas Protheus" ) oModel:GetModel( 'SM0MASTER' ):SetDescription( "Empresas Protheus" ) oModel:SetPrimaryKey( {"M0_CODIGO", "M0_CODFIL"} ) Return oModel Static Function DefStrModel() Local oStruct := FWFormModelStruct():New() Local bValid := { || .T.} Local bWhen := { || } Local bRelac := { || } // TABELA oStruct:AddTable( "SM0", {}, "Filiais", {|| }) // INDICES oStruct:AddIndex(1, "1", "M0_CODIGO", "Cód Empresa", "", "", .T.) // CAMPOS oStruct:AddField( "Cód Empresa" , "Cód Empresa" , "M0_CODIGO" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "Cód Filial" , "Cód Filial" , "M0_CODFIL" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "Nome Empresa" , "Nome Empresa" , "M0_NOMECOM", "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "CNPJ" , "CNPJ" , "M0_CGC" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "UF" , "UF" , "M0_ESTENT" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "Insc Estadual" , "Insc Estadual" , "M0_INSC" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "Insc Municipal", "Insc Municipal" , "M0_INSCM" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "Cód Munic" , "Cód Munic" , "M0_CODMUN" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "Nome Filial" , "Nome Filial" , "M0_FILIAL" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "Município" , "Município" , "M0_CIDENT" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "Inscrição" , "Inscrição" , "M0_INSCANT", "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "NIRE" , "NIRE" , "M0_NIRE" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "Data do Nire" , "Data do Nire" , "M0_DTRE" , "D", 08, 0, bValid, bWhen, , , bRelac, .F., , , ) oStruct:AddField( "End Cob" , "End Cob" , "M0_ENDCOB" , "C", 50, 0, bValid, bWhen, , , bRelac, .F., , , ) Return oStruct Static Function MyLoad() Local aRet := {} aRet := {{SM0->M0_CODIGO, SM0->M0_CODFIL, SM0->M0_NOMECOM, SM0->M0_CGC, SM0->M0_ESTENT, SM0->M0_INSC, SM0->M0_INSCM, SM0->M0_CODMUN,; SM0->M0_FILIAL, SM0->M0_CIDENT, SM0->M0_INSCANT, SM0->M0_NIRE, SM0->M0_DTRE, SM0->M0_ENDCOB}, ; SM0->(Recno())} Return aRet |
Status do documento | Concluído |
---|---|
Data | 25/06/2015 |
Versão | 1.0 |
Versão anterior | 1.0 |
Autores | Felipe Bonvicini Conti |