
Introdução
Dando continuidade a série de artigos sobre ReactJS + Advpl, hoje irei iniciar a API de CRUD com a parte de listar as permissões salvas na tabela Z20. Caso você tenha perdido alguma parte ou tenha interesse em ler os primeiros artigos dessa série, abaixo você tem uma lista contendo o título e o link de cada um deles.
- ADVPL + REACT – Parte 01 | Criação das tabelas
- ADVPL + REACT – Parte 02 | Servidor REST Protheus
- ADVPL + REACT – Parte 03 | Segurança e API de Login + BÔNUS
API de Consulta
Agora iremos entrar na parte mais interessante do backend da nossa aplicação, onde faremos endpoints para trabalhar com a inclusão, alteração, consulta e deleção dos dados na tabela Z20.
Vamos iniciar pela consulta (GET), onde o endpoint “/TPontinAccessControl” estará hapto a receber requisições do tipo GET e retornar via JSON todos os registros da tabela Z20.
Bora Codar!!!
Vamos começar criando uma classe responsável por gerar o objeto com o modelo de dados da Z20 conforme o dicionário de dados (SX3).
Faremos de forma que esse modelo seja o mais dinâmico possível, não necessitando de manutenção nos fontes em caso de criação de novos campos ou alterações no dicionário de dados da Z20.
Model
Vamos então criar uma pasta chamada “models” dentro da pasta “src” e em seguida criamos o nosso fonte “TPontinAccessControlModel.prw“, ficando no seguinte caminho: src/models/TPontinAccessControlModel.prw.
Agora basta incluir o código abaixo no nosso fonte:
#include 'totvs.ch'
//|Responsavel por montar o modelo de dados da Z20 |
Class TPontinAccessControlModel From LongClassName
Data oObjZ20
Method New() Constructor
EndClass
Method New() Class TPontinAccessControlModel
Local aZ20Struct := {}
Local nI := 0
dbSelectArea("Z20")
Z20->( dbSetOrder(1) )
aZ20Struct := Z20->( dbStruct() )
::oObjZ20 := JsonObject():New()
::oObjZ20['RECNO'] := 0
For nI := 1 To Len(aZ20Struct)
::oObjZ20[ aZ20Struct[nI,1] ] := CriaVar( aZ20Struct[nI,1], .T. )
Next nI
Return self
Explicando por partes…
Class TPontinAccessControlModel From LongClassName
Data oObjZ20
Method New() Constructor
EndClass
No trecho acima é criado a classe e informado que será utilizado a propriedade “oObjZ20”.
Logo em seguida informamos os métodos que serão criados na classe.
Method New() Class TPontinAccessControlModel
Local aZ20Struct := {}
Local nI := 0
dbSelectArea("Z20")
Z20->( dbSetOrder(1) )
aZ20Struct := Z20->( dbStruct() )
::oObjZ20 := JsonObject():New()
::oObjZ20['RECNO'] := 0
For nI := 1 To Len(aZ20Struct)
::oObjZ20[ aZ20Struct[nI,1] ] := CriaVar( aZ20Struct[nI,1], .T. )
Next nI
Return self
Linha 09: aZ20Struct := Z20->( dbStruct() )
Basicamente nesse ponto utilizamos a classe “dbStruct()” para buscar a estrutura de campos da Z20 direto no dicionário de dados, com isso caso um campo seja alterado ou incluído não será necessário realizar manutenção no nosso modelo.
Linha 13: ::oObjZ20[‘RECNO’] := 0
Foi criado também a propriedade “RECNO” no JsonObject do modelo para guardar o R_E_C_N_O_ do registro em questão para uso nos momentos de alteração e exclusão de registros.
Linha 15 a 19: For nI := 1 To Len(aZ20Struct) …
Utilizamos o FOR para percorrer todos os campos da Z20 e incluí-los no JsonObject, com isso conseguiremos obter os campos através do método “GetNames” da classe JsonObject e inserir os valores buscando do banco de dados através do DAO (data access object).
Data Access Object
Vamos agora criar o nosso DAO que será a camada responsável por toda a comunicação com o banco de dados.
Começamos criando uma pasta chamada “DAO” dentro da pasta “src” e em seguida criamos o nosso fonte “TPontinAccessControlDAO.prw“, ficando no seguinte caminho: src/models/TPontinAccessControlDAO.prw.
Agora incluímos o código abaixo no nosso fonte:
#include 'totvs.ch'
//|Responsavel por acesso ao banco de dados |
Class TPontinAccessControlDAO From LongClassName
Data oModel
Method New() Constructor
Method ListarZ20()
EndClass
Method New() Class TPontinAccessControlDAO
::oModel := TPontinAccessControlModel():New()
Return self
Method ListarZ20() Class TPontinAccessControlDAO
Local oObjRet := Nil
Local oDados := Nil
Local aArea := GetArea()
Local aAreaZ20 := Z20->( GetArea() )
Local aCampos := {}
Local aPermissao := {}
Local nPos := 0
Local nZ := 0
Local nCont := 0
dbSelectArea("Z20")
Z20->( dbSetOrder(1) )
Z20->( dbGoTop() )
oObjRet := JsonObject():New()
//|Busca todos os campos do model |
aCampos := ::oModel:oObjZ20:GetNames()
While !Z20->( EoF() )
oDados := TPontinAccessControlModel():New()
aAdd( aPermissao, oDados:oObjZ20 )
nPos := Len(aPermissao)
For nZ := 1 To Len(aCampos)
If aCampos[nZ] == 'RECNO'
aPermissao[ nPos, 'RECNO' ] := Z20->( Recno() )
Else
aPermissao[ nPos, aCampos[nZ] ] := AlLTrim( &( 'Z20->' + aCampos[nZ] ) )
EndIf
Next nZ
nCont++
Z20->( dbSkip() )
EndDO
oObjRet['registros'] := nCont
oOBjRet['result'] := JSonObject():New()
oObjRet['result'] := aPermissao
RestArea(aAreaZ20)
RestArea(aArea)
Return oObjRet
No código acima criamos a classe “TPontinAccessControlDAO” com a propriedade “oModel” e os métodos “New()” que é o construtor da classe e o método “ListarZ20()” que é responsável por buscar os dados na tabela Z20 e retorna-los em um JsonObject.
Explicando o método ListarZ20:
Linha 41: aCampos := ::oModel:oObjZ20:GetNames()
O array “aCampos” recebe os campos que estão no modelo da Z20 através do método GetNames() da classe JsonObject, inclusive com o campo RECNO que criamos.
Linha 43 a 64: While !Z20->( EoF() ) …
Percorre todos os itens gravados na Z20 e alimenta no array “aPermissao” com todos os campos da Z20 de forma dinâmica através da macro substituição do nome do campo: “&('Z20->'+aCampos[nZ])
“.
No final é alimentado o objeto “oObjRet” com a quantidade de registros encontrados e com o array “aPermissao” com os dados.
Com isso o nosso DAO já está preparado para buscar os dados da Z20 no banco de dados e retornar no objeto Json.
Controller
Agora podemos criar o controller que será responsável por receber as requisições REST. De início vamos criar dentro da pasta src/controllers o fonte: “TPontinAccessControl.prw” e vamos incluir o código abaixo para receber a requisição GET.
#include 'totvs.ch'
#include 'restful.ch'
WSRESTFUL TPontinAccessControl DESCRIPTION "Serviço REST para controle de acesso dos usuarios"
WSMETHOD GET DESCRIPTION "Retorna o cadastro de controle de acessos" ;
WSSYNTAX "/TPontinAccessControl"
END WSRESTFUL
WSMETHOD GET WSRECEIVE WSSERVICE TPontinAccessControl
Local oDAO := NIL
Local oDados := NIL
::SetContentType("application/json")
oDados := JsonObject():New()
oDAO := TPontinAccessControlDAO():New()
oDados := oDAO:ListarZ20()
::SetStatus(200)
::SetResponse( oDados:ToJson() )
Return .T.
A parte de WSRESTFUL e demais detalhes da API REST já foram explicadas anteriormente, então vamos forcar no método GET a partir da linha 20.
Linha 20: oDados := JsonObject():New()
Informo que a variável oDados será um objeto Json
Linha 22: oDAO := TPontinAccessControlDAO():New()
A variável oDAO recebe o resultado do método construtor do nosso DAO (Data Access Object)
Linha 23: oDados := oDAO:ListarZ20()
Executa o método “ListarZ20()” e insere o resultado na variável oDados
Linha 25: ::SetStatus(200)
Informo que irei retornar o status 200 (OK) para o solicitante dos dados. É interessante realizar o tratamento desse código de retorno seguindo as boas práticas, porém para esse exemplo vamos manter o 200.
Linha 26: ::SetResponse( oDados:ToJson() )
O método “ToJson()” fará a conversão do objeto criado pela classe JsonObject e alimentado pelo método “ListarZ20()” para um string no formato JSON e responderá o solicitante com o resultado.
Finalizando vamos compilar os três novos fontes (Model, DAO e Controller) e podemos testar.
Com os fontes compilados, iremos criar dois registros na Z20 via APSDU apenas para conseguir ver o resultado no Json, depois podemos excluí-los devido objetivo é serem inseridos via requisição POST.

Hora da verdade, vamos realizar a requisição desse endpoint no insomnia conforme imagem abaixo (lembre-se de realizar o login e pegar o token).

Resultado:

Show de bola, agora já temos o método GET buscando dados reais da nossa tabela de permissões via requisição REST.
Lembrando que os fontes estão disponíveis para todos no GitHub.
No próximo tópico iremos fazer o método POST com algumas validações básicas do body.
Se inscrevam no blog para receber em primeira mão as novidades dessa série e não perder nada do que rola por aqui.
O nosso objetivo é criar uma cultura de uso da tecnologia para tornar as empresas brasileiras mais competitivas, por isso compartilhem esses posts com seus amigos para que possamos atingir um número maior ainda de pessoas.
Até mais…