<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Josimar Junior</title>
    <description>The latest articles on DEV Community by Josimar Junior (@josimar_jr_).</description>
    <link>https://dev.to/josimar_jr_</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F267695%2F6c47cb76-92e3-4377-a4cc-af01f558fb24.jpg</url>
      <title>DEV Community: Josimar Junior</title>
      <link>https://dev.to/josimar_jr_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/josimar_jr_"/>
    <language>en</language>
    <item>
      <title>Um microblog usando Protheus - Rest Server, parte 5, GET e query parameters</title>
      <dc:creator>Josimar Junior</dc:creator>
      <pubDate>Sat, 26 Dec 2020 20:32:53 +0000</pubDate>
      <link>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-5-get-e-query-parameters-11ao</link>
      <guid>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-5-get-e-query-parameters-11ao</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Seguindo com a exploração dos modelos para construção dos métodos de apis utilizando Advpl no Rest Protheus, nesta publicação será abordado como fazer uso dos recursos de &lt;code&gt;query parameters&lt;/code&gt; e assim permitir pesquisa e exploração das informações no ERP.&lt;/p&gt;

&lt;p&gt;Na publicação anterior os métodos &lt;code&gt;POST&lt;/code&gt; na uri &lt;code&gt;/perfis&lt;/code&gt; e &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt; e &lt;code&gt;PUT&lt;/code&gt; na uri &lt;code&gt;/perfis/:id&lt;/code&gt; foram modificados para utilizar o modelo de dados do MVC Advpl como camada de interação com o banco de dados, o link para a publicação anterior está &lt;a href="https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-4-classe-para-rest-modelos-mvc-2fpk"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Entretanto um dos endpoints muito usado até então não foi modificado, o &lt;code&gt;GET&lt;/code&gt; na uri &lt;code&gt;/perfis&lt;/code&gt;. Este é o endpoint onde é conseguida a lista dos recursos oferecidos pela api. Essa modificação não aconteceu no passo anterior, pois não é possível realizar a recuperação de uma lista usando um modelo de dados que foi desenvolvido para lidar com um único registro.&lt;/p&gt;

&lt;p&gt;Em função disso, será mostrada uma alternativa de como implementar de forma simplificada:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;filtros utilizando expressões SQL limitadas a partir de dados informados na api;&lt;/li&gt;
&lt;li&gt;restrição das propriedades a serem retornadas, reduzindo o tamanho da resposta;&lt;/li&gt;
&lt;li&gt;paginação dos dados da api, essencial para avaliação de quantidade de itens e;&lt;/li&gt;
&lt;li&gt;definição da ordem dos dados na requisição.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deve ser ressaltado que a escolha de demonstrar a implementação desses recursos não assegura que o código resultante esteja pronto para apis que tenham necessidades avançadas, seja de desempenho, seja de complexidade da lógica de negócio envolvida. O código construído tem o objetivo de ser claro e mostrar exatamente onde as regras são extraídas e como são transformadas em cada um dos recursos.&lt;/p&gt;

&lt;h1&gt;
  
  
  Por que desenvolver estes recursos?
&lt;/h1&gt;

&lt;p&gt;Quando endpoints que oferecem a possibilidade de listagem dos itens não possuem flexibilidade de filtro ou pesquisa, é bem ruim ser um cliente dessa api, afinal todo o trabalho manipulação dos dados para exibição fica como responsabilidade do cliente, portanto, oferecer recursos para filtrar e controlar quais e como as propriedades devem ser retornadas é essencial para ser uma boa api.&lt;/p&gt;

&lt;p&gt;A Totvs possui um guia de implementação de apis para ser utilizado pelos times internamente e especificamente sobre retorno de coleções pode ser &lt;a href="https://tdn.totvs.com/display/public/INT/Guia+de+implementacao+das+APIs+TOTVS#GuiadeimplementacaodasAPIsTOTVS-Cole%C3%A7%C3%B5es"&gt;lido e avaliado aqui&lt;/a&gt;. O guia não será seguido nesta série apesar de várias semelhanças poderem ser identificadas.&lt;/p&gt;

&lt;h1&gt;
  
  
  A implementação
&lt;/h1&gt;

&lt;p&gt;Os recursos mencionados e criados para permitir a manipulação do retorno da coleção de &lt;code&gt;GET /perfis/&lt;/code&gt; foram:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;paginação: permitir que uma quantidade limitada de perfis sejam retornados por requisição no endpoint, o principal benefício é que um cliente consegue então exibir uma lista menor mais rápido e caso precise carregue mais itens com uma quantidade maior depois;&lt;/li&gt;
&lt;li&gt;ordenação: conseguir pelo cliente indicar a ordem que os resultados devem ser retornados, um exemplo é a ordenação por nome ou por data de criação que são usadas por razões diferentes no cliente, deixar a ordem fixa poderia atender somente uma das formas de uso;&lt;/li&gt;
&lt;li&gt;projeção de retorno: quando necessário os valores de somente uma ou duas propriedades de um certo endpoint, recuperar todas as propriedades e usar somente o que precisava é desperdício de recurso;&lt;/li&gt;
&lt;li&gt;filtro: este é um aspecto delicado, enquanto é um excelente recurso e provavelmente o mais necessário, oferecer essa possibilidade implica em cuidado extra para evitar códigos maliciosos serem injetados no programa durante a execução.&lt;/li&gt;
&lt;li&gt;contagem: quando filtro é permitido no endpoint, a contagem passa a ter complicações para execução, pois o filtro precisa ser considerado também. O principal objetivo da contagem é indicar que existem ou não mais itens para carregar pelo cliente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A seguir os detalhes da implementação dos recursos, de forma simplificada mostrando como que o Rest Protheus oferece e como fazer em Advpl.&lt;/p&gt;

&lt;h2&gt;
  
  
  A base
&lt;/h2&gt;

&lt;p&gt;Para a construção destes recursos a primeira alteração foi trocar a iteração sobre a tabela &lt;code&gt;ZT0&lt;/code&gt; com &lt;code&gt;while&lt;/code&gt; e &lt;code&gt;DbSkip&lt;/code&gt; para a execução de uma consulta SQL na recuperação dos perfis a serem retornados. O ganho com esta simples alteração é a possibilidade de construção dinâmica da query, com os cuidados especiais para não causar quebras por entradas incorretas informadas na requisição.&lt;/p&gt;

&lt;p&gt;A implementação mostrada ainda pode ter quebras em condições bem específicas de uso, então se tem a intenção de usar como base para sua api, teste bem!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;oPrepStat&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;FwPreparedStatement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cDataQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetLike&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_VALUE&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;cDataQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getFixQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cTempAlias&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;GetNextAlias&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;DbUseArea&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt; &lt;span class="s"&gt;"TOPCONN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TcGenQry&lt;/span&gt;&lt;span class="p"&gt;(,,&lt;/span&gt; &lt;span class="n"&gt;cDataQuery&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Acima a classe &lt;code&gt;FwPreparedStatement&lt;/code&gt; é usada para ajudar na construção da consulta SQL, essa classe colabora com a avaliação de instruções maliciosas que vieram pelos &lt;code&gt;query parameters&lt;/code&gt; com as chaves que irão tornar-se componentes na consulta. &lt;br&gt;
Uma opção a &lt;a href="https://tdn.totvs.com/display/public/PROT/FWPreparedStatement"&gt;FwPreparedStatement&lt;/a&gt; é a função &lt;a href="https://tdn.totvs.com/display/tec/TCGenQry2"&gt;TcGenQry2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A outra alteração que serviu de base para a implementação foi a utilização de um mapa entre os campos na tabela e as propriedades retornadas pelo endpoint. O ganho com isso é a facilidade para descobrir o campo que certa propriedade se refere, assim os recursos são implementados de forma mais "simplificada".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Mapeia os campos da query com as propriedades&lt;/span&gt;
&lt;span class="n"&gt;aFieldsMap&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_EMAIL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_EMAIL"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_USRID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_USRID"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_NOME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_NOME"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_ADMIN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_ADMIN"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"inserted_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_INS_AT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"I_N_S_D_T_"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_UPD_AT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"S_T_A_M_P_"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  As propriedades usadas
&lt;/h2&gt;

&lt;p&gt;A lista dos componentes de &lt;code&gt;query parameters&lt;/code&gt; utilizados para permitir essas operações é apresentada a seguir.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;page&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pagesize&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fields&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aQueryString&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A paginação
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;page&lt;/code&gt; e &lt;code&gt;pagesize&lt;/code&gt;: a combinação que permite receber &lt;code&gt;?page=1&amp;amp;pagesize=10&lt;/code&gt; e construir um retorno com os primeiros 10 itens da 1a página e também permite a requisição como &lt;code&gt;?page=11&amp;amp;pagesize=6&lt;/code&gt; em que 11a página será exibida com 6 itens. Isso é relevante demais para páginas web ou aplicativos que no carregamento inicial não precisam de um volume grande de itens para exibição. O conceito de paginação por completo precisa ainda de uma indicação da existência de mais itens e isso é atendido com a contagem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Os trechos de código destacados para paginação estão a seguir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsreceive&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// montagem da paginação&lt;/span&gt;
&lt;span class="n"&gt;nItemFrom&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;nItemTo&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;cProjQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"ROW_NUMBER() OVER (order by "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;xyz&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;") SEQITEM "&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;cDataQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"where SEQITEM &amp;gt;= "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cValToChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nItemFrom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;" and SEQITEM &amp;lt;= "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cValToChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nItemTo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em resumo, (1) receber os &lt;code&gt;query parameters&lt;/code&gt;, (2) garantir valor padrão e então (3) utilizar o recurso &lt;code&gt;ROW_NUMBER() OVER&lt;/code&gt; na consulta SQL para a recuperação dos registros e a marcação de sequência que posteriormente já chega filtrada na camada Advpl. Sem necessidade de &lt;code&gt;if&lt;/code&gt; ou incrementos no Advpl.&lt;/p&gt;

&lt;h2&gt;
  
  
  A ordenação
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;order&lt;/code&gt;: a chave que permite indicar qual a ordem que o retorno dos dados deve seguir, receber a instrução &lt;code&gt;?order=name&lt;/code&gt; indica que ordenar pela propriedade &lt;code&gt;name&lt;/code&gt;, independente do que esta propriedade signifique internamente no endpoint e receber &lt;code&gt;?order=-inserted_at,name&lt;/code&gt; indica retornar por ordem inversa de criação (sendo os mais recentes primeiro) e ordem alfabética dos nomes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Os trechos de código a serem destacados sobre ordenação estão a seguir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsreceive&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// montagem da ordem&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;aTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;StrTokArr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;nMax&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aTemp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;cOrderBy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;nMax&lt;/span&gt;
        &lt;span class="c1"&gt;// um monte de código para identificar os campos e ordenação&lt;/span&gt;
        &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;
        &lt;span class="c1"&gt;// Remove a última vírgula (,)&lt;/span&gt;
        &lt;span class="n"&gt;cOrderBy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;SubStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cOrderBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cOrderBy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cOrderBy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cOrderBy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"ZT0_NOME asc"&lt;/span&gt;
&lt;span class="n"&gt;endif&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;cProjQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"ROW_NUMBER() OVER (order by "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cOrderBy&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;") SEQITEM "&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este é o primeiro dos recursos permitidos que exige algoritmo para identificar a lista das propriedades e os campos que precisarão ser utilizados neste ordenação, receber &lt;code&gt;?order=-age,name&lt;/code&gt; significa reconhecer os campos ou expressões associados com estas propriedades e neste caso, usando o mapa mencionado anteriormente. Por último usar esta expressão na consulta SQL e assim garantir a ordenação em conjunto com a marcação e sequenciamento dos registros pela função &lt;code&gt;ROW_NUMBER() OVER(order) nome_da_coluna&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Alguns bancos de dados podem não suportar a ordenação em conjunto com a paginação, vale estudar o banco de dados e versão utilizada para garantir o máximo possível ainda em nível de banco de dados e não na camada Advpl.&lt;/p&gt;

&lt;h2&gt;
  
  
  A projeção
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fields&lt;/code&gt;: a chave por onde são indicadas as propriedades que devem ser retornadas do recurso pesquisado, um exemplo é retornar somente &lt;code&gt;email&lt;/code&gt; e &lt;code&gt;name&lt;/code&gt; quando recebido &lt;code&gt;?fields=email,name&lt;/code&gt;. Isso facilita os inúmeros casos quando poucas informações são exigidas em uma requisição, mas o item possui outras várias propriedades. Esta é mais uma das propriedades que utiliza do mapa de propriedades e campos como referência para sua execução.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Os trechos para destaque da projeção de propriedades da api estão a seguir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsreceive&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// monta as propriedades escolhidas para retorno&lt;/span&gt;
&lt;span class="n"&gt;aRetProps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;StrTokArr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;nRetProps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aRetProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nRetProps&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;aRetProps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"inserted_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;nRetProps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aRetProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;endif&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;jTempItem&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aTail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;nRetProps&lt;/span&gt;
    &lt;span class="c1"&gt;// recupera o nome da propriedade&lt;/span&gt;
    &lt;span class="n"&gt;cTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aRetProps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;// recupera o mapa propriedade x campo&lt;/span&gt;
    &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aScan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAP_PROP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="c1"&gt;// recupera o valor para a propriedade&lt;/span&gt;
        &lt;span class="n"&gt;xPropValue&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FieldGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FieldPos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_FIELD&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;

        &lt;span class="c1"&gt;// atribui o valor na propriedade&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;
            &lt;span class="n"&gt;jTempItem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;RTrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xPropValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;
            &lt;span class="n"&gt;jTempItem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;xPropValue&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;jTempItem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;xPropValue&lt;/span&gt;
        &lt;span class="n"&gt;endif&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;
&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os passos na implementação são (1) recuperar as propriedades indicadas para retorno, (2) transformar em lista usando o mapa, com o cuidado de limitar as propriedades de retorno apropriadas e (3) montar a resposta considerando o recebido na requisição.&lt;/p&gt;

&lt;p&gt;A montagem do retorno está longe de ter o código mais apropriado e genérico, contudo dá uma excelente indicação do quão complicado é lidar com tipos e expressões retornadas da tabela para a api.&lt;/p&gt;

&lt;h2&gt;
  
  
  O filtro
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;propriedade=valor&lt;/code&gt;: este é o recurso que não está associado com uma chave específica. Filtros avançados e com expressões complexas estão associados com o parâmetro &lt;code&gt;?filter=expressão&lt;/code&gt;, contudo a construção de um parser para expressões e complicada demais para ser simplificada e demonstrada nessa série, em função disso o caminho para mostrar filtros de uma forma que funcione minimamente são os filtros como este, &lt;code&gt;?admin=true&lt;/code&gt; onde indica os perfis de administradores, ou &lt;code&gt;?name=a&amp;amp;admin=true&lt;/code&gt; em que montaria uma condição SQL similar à &lt;code&gt;ZT0_NOME like '%a%' and ZT0_ADMIN = '1'&lt;/code&gt; e retornaria os perfis com a letra &lt;code&gt;a&lt;/code&gt; minúscula no nome e são administradores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com os exemplos indicados é possível perceber que usando o mapa de propriedades x campos existe a chance de trocar o tipo de operador conforme o tipo ou nome do campo/propriedade ou qualquer outra lógica, a decisão no código de exemplo foi usar a comparação com o operador &lt;code&gt;like&lt;/code&gt; para caracteres, a operação &lt;code&gt;= '1'&lt;/code&gt; para a propriedade &lt;code&gt;admin&lt;/code&gt; e a operação &lt;code&gt;=&lt;/code&gt; para os demais campos. Qualquer comparação com operadores diferentes exigiria a implementação de mais complexidade na montagem da expressão a ser recebida na requisição para o filtro e consequentemente mais complexidade para identificar o que fazer e montar a consulta SQL.&lt;/p&gt;

&lt;p&gt;Os trechos importantes para a implementação são apresentados a seguir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// monta a condição para a query&lt;/span&gt;
&lt;span class="c1"&gt;//  suporta filtros simples com operador LIKE -&amp;gt; campo like %valor%&lt;/span&gt;
&lt;span class="n"&gt;cCondition&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"ZT0.D_E_L_E_T_ = ' ' "&lt;/span&gt;
&lt;span class="n"&gt;aQryValues&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;To&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;aQueryString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cTempField&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Lower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;aQueryString&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_PARAM_KEY&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aScan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAP_PROP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;cTempField&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="c1"&gt;// quando encontra cria a expressão e guarda o valor para atribuir&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;
            &lt;span class="n"&gt;cCondition&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"and ZT0."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_FIELD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" like ? "&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;cCondition&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"and ZT0."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_FIELD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" = ? "&lt;/span&gt;
        &lt;span class="n"&gt;endif&lt;/span&gt;
        &lt;span class="c1"&gt;// mantem par com tipo [QRY_VAL_TYPE] e valor [QRY_VAL_VALUE]&lt;/span&gt;
        &lt;span class="n"&gt;aAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_TYPE&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;aQueryString&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_PARAM_VALUE&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;
&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// tabela e condições&lt;/span&gt;
&lt;span class="n"&gt;cSubQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"from "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;RetSqlName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" ZT0 "&lt;/span&gt;
&lt;span class="n"&gt;cSubQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"where "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cCondition&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// query para os dados&lt;/span&gt;
&lt;span class="n"&gt;cDataQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"select * "&lt;/span&gt;
&lt;span class="n"&gt;cDataQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"from ( "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cProjQuery&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cSubQuery&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" ) QUERYDATA "&lt;/span&gt;
&lt;span class="n"&gt;cDataQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"where SEQITEM &amp;gt;= "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cValToChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nItemFrom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;" and SEQITEM &amp;lt;= "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cValToChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nItemTo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os passos para realizar o filtro são os mais complexos, envolve (1) percorrer todas as propriedades recebidas por &lt;code&gt;query parameters&lt;/code&gt;, (2) identificar os componentes que são propriedades válidas para o filtro (mais uma vez o mapa em ação), (3) verificar qual operador utilizar conforme propriedade e campo na consulta SQL, (4) marcar o valor para ser preenchido com &lt;code&gt;?&lt;/code&gt; pois depois será substituído pelo valor com uso da classe &lt;code&gt;FwPreparedStatement&lt;/code&gt;, (4) substituir o valor e finalmente (5) montar e executar a query com a condição interferindo no resultado da paginação (expressão &lt;code&gt;ROW_NUMBER OVER()&lt;/code&gt;).&lt;br&gt;
Essa dificuldade é paga quando o retorno da api é minimizado e quando a aplicação cliente não precisa aplicar uma preparação pesada para lidar com os dados!&lt;/p&gt;
&lt;h2&gt;
  
  
  A contagem
&lt;/h2&gt;

&lt;p&gt;O único dos recursos que não é um pedido do cliente e sim um retorno adicional para a paginação. Sem a indicação da quantidade de registros totais, a aplicação cliente precisaria fazer uma requisição e não ter dado retornado para saber que "acabou" e não há mais dados. Com a indicação da quantidade total com alguma propriedade como &lt;code&gt;total&lt;/code&gt;, &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;quantity&lt;/code&gt;, etc é possível informar ao cliente o número de registros e evitar uma última requisição sem dado para retornar.&lt;/p&gt;

&lt;p&gt;Um modelo alternativo é o seguido pelo &lt;a href="https://tdn.totvs.com/display/public/INT/Guia+de+implementacao+das+APIs+TOTVS#GuiadeimplementacaodasAPIsTOTVS-Cole%C3%A7%C3%B5es"&gt;guia de api da Totvs&lt;/a&gt; com o uso da propriedade &lt;code&gt;has_next&lt;/code&gt;, com detalhes neste &lt;a href="https://tdn.totvs.com/display/public/INT/Guia+de+implementacao+das+APIs+TOTVS#GuiadeimplementacaodasAPIsTOTVS-ApiSuccessMsgCollMensagensdesucessoparacole%C3%A7%C3%B5es"&gt;link&lt;/a&gt;. O benefício com esta propriedade é indicar de forma simplificada para o cliente a existência de mais registros para a busca, o contra-ponto é não conseguir indicar o total de registros só com ela.&lt;/p&gt;

&lt;p&gt;Os detalhes da implementação deste retorno estão a seguir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Recupera a quantidade de registros&lt;/span&gt;
&lt;span class="n"&gt;cCountQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"select count(*) ROWS_QT "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cSubQuery&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;oPrepStat&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;FwPreparedStatement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cCountQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// lógica para preencher as marcações com ? da query&lt;/span&gt;
&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;

&lt;span class="n"&gt;cCountQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getFixQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;DbUseArea&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt; &lt;span class="s"&gt;"TOPCONN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TcGenQry&lt;/span&gt;&lt;span class="p"&gt;(,,&lt;/span&gt; &lt;span class="n"&gt;cCountQuery&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;nCount&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;nCount&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ROWS_QT&lt;/span&gt;
&lt;span class="n"&gt;endif&lt;/span&gt;
&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nCount&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois de entender como funciona a consulta SQL para a recuperação dos dados, não há segredo na consulta SQL de fazer a contagem, afinal única alteração que acontece é a substituição da lista de campos da expressão &lt;code&gt;select&lt;/code&gt; por &lt;code&gt;count(*)&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusão
&lt;/h1&gt;

&lt;p&gt;Esta é a primeira publicação da série que apresenta alta quantidade de código, conceitos e também o uso das propriedades da classe e métodos do rest com Advpl. Tudo isso implica em conteúdo denso para assimilar e entender com profundidade.&lt;/p&gt;

&lt;p&gt;O código apresentado tem muito a ser melhorado e pode ser utilizado em uma api em produção com as melhorias apropriadas para casos específicos. Um código similar ao mostrado nesta publicação foi base para a implementação da classe &lt;a href="https://tdn.totvs.com/pages/viewpage.action?pageId=555254105"&gt;FwAdapterBaseV2&lt;/a&gt;, que possui estes conceitos encapsulados e pode ser usada na construção de apis. A próxima publicação será uma terceira versão desse endpoint de listagem usando a classe &lt;a href="https://tdn.totvs.com/pages/viewpage.action?pageId=555254105"&gt;FwAdapterBaseV2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;O código a seguir mostra a implementação completa de método de listagem, que também pode ser visualizado no &lt;a href="https://github.com/josimar-jr/microblog-protheus/pull/3/files#diff-c3c55acd073b3b9f7291979029698bb4fd26b02c4a36fc0cb03b485af74afacbR568"&gt;pull request no GitHub&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;GET&lt;/span&gt; &lt;span class="n"&gt;V2ALL&lt;/span&gt; &lt;span class="n"&gt;wsreceive&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="n"&gt;wsservice&lt;/span&gt; &lt;span class="n"&gt;Perfis&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;    &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;logical&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;     &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;jTempItem&lt;/span&gt;     &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cTempAlias&lt;/span&gt;    &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cDataQuery&lt;/span&gt;    &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;    &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;nItemFrom&lt;/span&gt;     &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;numeric&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;nItemTo&lt;/span&gt;       &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;numeric&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cOrderBy&lt;/span&gt;      &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cOrdDirection&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lDesc&lt;/span&gt;         &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;logical&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;aTemp&lt;/span&gt;         &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cTempField&lt;/span&gt;    &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;nTemp&lt;/span&gt;         &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;numeric&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;            &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;numeric&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;nMax&lt;/span&gt;          &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;numeric&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cCondition&lt;/span&gt;    &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;aQryValues&lt;/span&gt;    &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;oPrepStat&lt;/span&gt;     &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;aRetProps&lt;/span&gt;     &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;nRetProps&lt;/span&gt;     &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;numeric&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;xPropValue&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;nCount&lt;/span&gt;        &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;numeric&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cCountQuery&lt;/span&gt;   &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cProjQuery&lt;/span&gt;    &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cSubQuery&lt;/span&gt;     &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="c1"&gt;// Define o tipo de retorno do método&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetContentType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// As propriedades da classe receberão os valores enviados por querystring&lt;/span&gt;
    &lt;span class="c1"&gt;// exemplo: /rest/microblog/v1/perfis?page=1&amp;amp;pageSize=5&amp;amp;order=-name&amp;amp;fields=name,email&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
    &lt;span class="c1"&gt;// Mapeia os campos da query com as propriedades&lt;/span&gt;
    &lt;span class="n"&gt;aFieldsMap&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_EMAIL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_EMAIL"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_USRID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_USRID"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_NOME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_NOME"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_ADMIN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_ADMIN"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"inserted_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_INS_AT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"I_N_S_D_T_"&lt;/span&gt;&lt;span class="p"&gt;},;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0_UPD_AT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"S_T_A_M_P_"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// montagem da paginação&lt;/span&gt;
    &lt;span class="n"&gt;nItemFrom&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;nItemTo&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt;

    &lt;span class="c1"&gt;// montagem da ordem&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;aTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;StrTokArr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;nMax&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aTemp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;cOrderBy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;nMax&lt;/span&gt;

            &lt;span class="n"&gt;lDesc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SubStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aTemp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lDesc&lt;/span&gt;
                &lt;span class="n"&gt;cTempField&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;SubStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aTemp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;cOrdDirection&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;" desc"&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
                &lt;span class="n"&gt;cTempField&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aTemp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;cOrdDirection&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;" asc"&lt;/span&gt;
            &lt;span class="n"&gt;endif&lt;/span&gt;

            &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aScan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAP_PROP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;cTempField&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                &lt;span class="n"&gt;cOrderBy&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_INTERNAL_FIELD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cOrdDirection&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;
            &lt;span class="n"&gt;endif&lt;/span&gt;
        &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;
        &lt;span class="c1"&gt;// Remove a última vírgula (,)&lt;/span&gt;
        &lt;span class="n"&gt;cOrderBy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;SubStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cOrderBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cOrderBy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cOrderBy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cOrderBy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"ZT0_NOME asc"&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;

    &lt;span class="c1"&gt;// monta a condição para a query&lt;/span&gt;
    &lt;span class="c1"&gt;//  suporta filtros simples com operador LIKE -&amp;gt; campo like %valor%&lt;/span&gt;
    &lt;span class="n"&gt;cCondition&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"ZT0.D_E_L_E_T_ = ' ' "&lt;/span&gt;
    &lt;span class="n"&gt;aQryValues&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;To&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;aQueryString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cTempField&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Lower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;aQueryString&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_PARAM_KEY&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aScan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAP_PROP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;cTempField&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;// quando encontra cria a expressão e guarda o valor para atribuir&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;
                &lt;span class="n"&gt;cCondition&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"and ZT0."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_FIELD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" like ? "&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
                &lt;span class="n"&gt;cCondition&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"and ZT0."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_FIELD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" = ? "&lt;/span&gt;
            &lt;span class="n"&gt;endif&lt;/span&gt;
            &lt;span class="c1"&gt;// mantem par com tipo [QRY_VAL_TYPE] e valor [QRY_VAL_VALUE]&lt;/span&gt;
            &lt;span class="n"&gt;aAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_TYPE&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;aQueryString&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_PARAM_VALUE&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;endif&lt;/span&gt;
    &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;

    &lt;span class="c1"&gt;// campos mapeados&lt;/span&gt;
    &lt;span class="n"&gt;cProjQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"select ZT0_EMAIL, ZT0_USRID, ZT0_NOME, ZT0_ADMIN,"&lt;/span&gt;
    &lt;span class="n"&gt;cProjQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"convert(varchar(23), I_N_S_D_T_, 21) ZT0_INS_AT,"&lt;/span&gt;
    &lt;span class="n"&gt;cProjQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"convert(varchar(23), S_T_A_M_P_, 21) ZT0_UPD_AT,"&lt;/span&gt;
    &lt;span class="n"&gt;cProjQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"ROW_NUMBER() OVER (order by "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cOrderBy&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;") SEQITEM "&lt;/span&gt;

    &lt;span class="c1"&gt;// tabela e condições&lt;/span&gt;
    &lt;span class="n"&gt;cSubQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"from "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;RetSqlName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" ZT0 "&lt;/span&gt;
    &lt;span class="n"&gt;cSubQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"where "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cCondition&lt;/span&gt;

    &lt;span class="c1"&gt;// query para os dados&lt;/span&gt;
    &lt;span class="n"&gt;cDataQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"select * "&lt;/span&gt;
    &lt;span class="n"&gt;cDataQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"from ( "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cProjQuery&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cSubQuery&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" ) QUERYDATA "&lt;/span&gt;
    &lt;span class="n"&gt;cDataQuery&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"where SEQITEM &amp;gt;= "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cValToChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nItemFrom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;" and SEQITEM &amp;lt;= "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cValToChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nItemTo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;

    &lt;span class="n"&gt;oPrepStat&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;FwPreparedStatement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cDataQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// atribui os valores de string com operador like&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;
            &lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetLike&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_VALUE&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="c1"&gt;// propriedade admin está com tipo lógico então faz igualdade 1=sim;2=não&lt;/span&gt;
        &lt;span class="n"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_VALUE&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_VALUE&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;cTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
                &lt;span class="n"&gt;cTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"2"&lt;/span&gt;
            &lt;span class="n"&gt;endif&lt;/span&gt;
            &lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;endif&lt;/span&gt;
    &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;

    &lt;span class="n"&gt;cDataQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getFixQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;cTempAlias&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;GetNextAlias&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;DbUseArea&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt; &lt;span class="s"&gt;"TOPCONN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TcGenQry&lt;/span&gt;&lt;span class="p"&gt;(,,&lt;/span&gt; &lt;span class="n"&gt;cDataQuery&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;

    &lt;span class="n"&gt;jResponse&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="c1"&gt;// monta as propriedades escolhidas para retorno&lt;/span&gt;
    &lt;span class="n"&gt;aRetProps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;StrTokArr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;nRetProps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aRetProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nRetProps&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;aRetProps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"inserted_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;nRetProps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aRetProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;aAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;jTempItem&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aTail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;nRetProps&lt;/span&gt;
            &lt;span class="c1"&gt;// recupera o nome da propriedade&lt;/span&gt;
            &lt;span class="n"&gt;cTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aRetProps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="c1"&gt;// recupera o mapa propriedade x campo&lt;/span&gt;
            &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aScan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAP_PROP&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nTemp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                &lt;span class="c1"&gt;// recupera o valor para a propriedade&lt;/span&gt;
                &lt;span class="n"&gt;xPropValue&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FieldGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FieldPos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_FIELD&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;

                &lt;span class="c1"&gt;// atribui o valor na propriedade&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;
                    &lt;span class="n"&gt;jTempItem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;RTrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xPropValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;aFieldsMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAP_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;
                    &lt;span class="n"&gt;jTempItem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;xPropValue&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;
                    &lt;span class="n"&gt;jTempItem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;xPropValue&lt;/span&gt;
                &lt;span class="n"&gt;endif&lt;/span&gt;
            &lt;span class="n"&gt;endif&lt;/span&gt;
        &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbSkip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;enddo&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbCloseArea&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="c1"&gt;// Recupera a quantidade de registros&lt;/span&gt;
    &lt;span class="n"&gt;cCountQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"select count(*) ROWS_QT "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cSubQuery&lt;/span&gt;

    &lt;span class="n"&gt;oPrepStat&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;FwPreparedStatement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cCountQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// atribui os valores de string com operador like&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;
            &lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetLike&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_VALUE&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="c1"&gt;// propriedade admin está com tipo lógico então faz igualdade 1=sim;2=não&lt;/span&gt;
        &lt;span class="n"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_TYPE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_VALUE&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aQryValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRY_VAL_VALUE&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;cTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
                &lt;span class="n"&gt;cTemp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"2"&lt;/span&gt;
            &lt;span class="n"&gt;endif&lt;/span&gt;
            &lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cTemp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;endif&lt;/span&gt;
    &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;nI&lt;/span&gt;

    &lt;span class="n"&gt;cCountQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oPrepStat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getFixQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;DbUseArea&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt; &lt;span class="s"&gt;"TOPCONN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TcGenQry&lt;/span&gt;&lt;span class="p"&gt;(,,&lt;/span&gt; &lt;span class="n"&gt;cCountQuery&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;nCount&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;nCount&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cTempAlias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ROWS_QT&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;
    &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nCount&lt;/span&gt;

    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>rest</category>
      <category>advpl</category>
      <category>api</category>
      <category>protheus</category>
    </item>
    <item>
      <title>Um microblog usando Protheus - Rest Server, parte 4, classe para rest + modelos MVC</title>
      <dc:creator>Josimar Junior</dc:creator>
      <pubDate>Mon, 07 Dec 2020 00:41:55 +0000</pubDate>
      <link>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-4-classe-para-rest-modelos-mvc-2fpk</link>
      <guid>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-4-classe-para-rest-modelos-mvc-2fpk</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Nesta parte da série de publicações será abordado como construir o conjunto de operações para incluir, buscar, atualizar e excluir um item utilizando um modelo de dados MVC para as operações que envolvem o banco de dados.&lt;br&gt;
Para essa demonstração o modelo de dados utilizado é o construído na &lt;a href="https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-3-1j2k"&gt;parte anterior&lt;/a&gt;, onde foi demonstrado como fazer a publicação de um modelo MVC no Rest e utilizada as URLs padrões &lt;code&gt;/fwmodel/{modelo}/{pk}&lt;/code&gt; para realizar as requisições rest. Portanto, em caso de dúvida da implementação do modelo usando nas operações a seguir consulte o código advpl no &lt;a href="https://github.com/josimar-jr/microblog-protheus/blob/6428ea4299dad6f34cd1723b9f712651f02064b4/src/perfis/ZMBA010.prw#L27"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Por que esta implementação?
&lt;/h1&gt;

&lt;p&gt;A implementação demonstrada a seguir não muda muito da demonstrada na &lt;a href="https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-2-1bch"&gt;segunda parte desta série&lt;/a&gt;, contudo a diferença que existe já proporciona um isolamento de responsabilidades melhor e para algumas situações específicas é uma implementação boa o bastante.&lt;br&gt;
O principal ganho desta implementação comparado com a demonstrada na segunda parte está no fato de que as validações e a gravação dos registros quando inclusão, alteração e exclusão não ficam na mesma função da api/requisição e sim em uma camada interna que pode evoluir de forma independente. Essa independência é relevante para a evolução dos serviços e contextos de negócios envolvidos na api.&lt;br&gt;
Existem várias abordagens com o propósito de separar essas camadas de responsabilidade, mas este não será o momento de explorar qualquer um destes modelos com Advpl e Protheus, isso será feito mais adiante na série. Para as pessoas que possuirem interesse em pesquisar neste momento, alguns dos temas e termos eles são N Layers, Hexagonal Architecture, Clean Architecture, Actors Model e a Orientação a Objetos no design de aplicações, estes são os que lembro no momento.&lt;/p&gt;
&lt;h1&gt;
  
  
  O efeito do modelo de dados no Protheus!
&lt;/h1&gt;

&lt;p&gt;Um dos principais recursos que o MVC Advpl oferece é a possibilidade de utilizar um determinado contexto de negócio em outros processos ou entidades, seja este primeiro modelo uma entidade ou um processo. Com isso é possível por exemplo na operação de criação de um registro na tabela A, também inserir um registro na tabela B ou qualquer outra entidade que estenda informações do registro na tabela A e tudo isso sem ferir regras de integridade e validações de negócio envolvidos em cada uma dessas tabelas.&lt;br&gt;
Isso é conseguido com o comando &lt;code&gt;FwLoadModel("arquivo")&lt;/code&gt; que recupera a definição do modelo de dados dentro da &lt;code&gt;static function ModelDef()&lt;/code&gt; e depois disso permite indicar a operação e os dados para criar, recuperar, atualizar ou excluir os registros.&lt;br&gt;
Esta possibilidade de reuso das regras é o que inibe a replicação de diversas validações, inclusive eventuais regras que não estão no dicionário de campos/SX3, e como vantagem adicional a gravação dos dados no modelo pode ser específica deste modelo e isso também será reutilizado.&lt;br&gt;
O único aspecto que acaba não sendo atendido com o uso do modelo MVC combinado com a classe Rest é a listagem dos registros. Isso por que quando utilizado através de tela no Smartclient dentro do Protheus a responsabilidade de listar os itens é do browse e por isso não há implementação no MVC que exiba uma lista por padrão. Em função disso os métodos apresentados a seguir são para operações em um item, um único registro.&lt;br&gt;
Para as pessoas que não entenderam e se perguntaram como a publicação do modelo padrão lida com isso e se perguntaram "Como a &lt;code&gt;/fwmodel/&lt;/code&gt; faz a listagem?" leia o modo avançado da &lt;a href="https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-3-1j2k"&gt;parte anterior&lt;/a&gt; nesta &lt;a href="https://tdn.totvs.com/display/public/PROT/FWRestModel"&gt;documentação&lt;/a&gt; e veja a implementação base da classe &lt;code&gt;FwRestModelObject&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Construindo a v2 para api de Perfis
&lt;/h1&gt;

&lt;p&gt;Será apresentada a versão 2 da api para Perfis do microblog e os aspectos que mudaram da v1 para a v2 que serão destacados.&lt;br&gt;
Os comandos relacionados à classe rest Advpl já mencionados não serão explicados novamente, caso tenha dúvida nestes pontos pode consulta a &lt;a href="https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-2-1bch"&gt;segunda parte da série&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  POST /microblog/v2/perfis/
&lt;/h2&gt;

&lt;p&gt;A operação de inclusão na &lt;code&gt;v1&lt;/code&gt; utilizava &lt;code&gt;Reclock&lt;/code&gt; e &lt;code&gt;MsUnlock&lt;/code&gt; e só validava a existência dos conteúdos que vieram no &lt;code&gt;body&lt;/code&gt; da requisição e esse tipo de validação é insuficiente para 99% dos casos.&lt;br&gt;
Isso se tornou os seguintes comandos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="nl"&gt;oModel:&lt;/span&gt;&lt;span class="n"&gt;SetOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MODEL_OPERATION_INSERT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Activate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;oZT0Header&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;GetModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0_FIELDS"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oZT0Header&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0_EMAIL"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oZT0Header&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0_USRID"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oZT0Header&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0_NOME"&lt;/span&gt;  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;VldData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CommitData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O número de linhas aumentou e o código pode ter ficado mais complicado, mas os benefícios já mencionados são garantidos com estas linhas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:SetValue("ZT0_EMAIL" , jBody["email"])&lt;/code&gt; =&amp;gt; quando adicionada uma validação para o campo de email ela passará a ser aplicada aqui.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;oModel:VldData() .And. oModel:CommitData()&lt;/code&gt; =&amp;gt; quando alterada a validação geral do modelo ou como a gravação acontece elas também estarão disponíveis aqui.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GET /microblog/v2/perfis/{perfilId}
&lt;/h2&gt;

&lt;p&gt;A recuperação de um registro usando o modelo MVC acontece da seguinte forma.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbSeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xFilial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MODEL_OPERATION_VIEW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Activate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;
    &lt;span class="n"&gt;oZT0Header&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;GetModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0_FIELDS"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oZT0Header&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0_EMAIL"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;oModel:Activate()&lt;/code&gt; =&amp;gt; comando que baseado no registro posicionado na tabela realiza a carga dos dados.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:GetValue("ZT0_EMAIL")&lt;/code&gt; =&amp;gt; como a informação do campo é recuperada e redirecionada para a resposta.
No caso da api para perfis quase não há vantagem entre o &lt;code&gt;DbSeek&lt;/code&gt; e a leitura direto do registro na tabela (ZT0-&amp;gt;ZT0_EMAIL) para o modelo, pois é um único registro. Isso muda de situação quando o cenário da api é por exemplo para publicações e comentários de uma publicação, como é exigido carregar elementos associados (a lista de comentários de uma publicação ou à qual publicação um comentário pertence), simplesmente posicionar nas tabelas não resolve, o uso do modelo ganha vantagem pois essa lógica e o eventual relacionamento usado estão na definição do modelo e só são usados pelo serviço da api com o modelo MVC instanciado.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  PUT /microblog/v2/perfis/{perfilId}
&lt;/h2&gt;

&lt;p&gt;A alteração e atualização dos campos acontece já utilizando os comandos mencionados nas operações de &lt;code&gt;POST&lt;/code&gt;e &lt;code&gt;GET&lt;/code&gt; e não há nenhum comando ou método novo do modelo MVC.&lt;br&gt;
O que muda é a operação definida antes do &lt;code&gt;Activate&lt;/code&gt; do modelo.&lt;br&gt;
Então a seguir as principais linhas em Advpl na classe do Rest para suportar a operação &lt;code&gt;PUT&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbSeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xFilial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MODEL_OPERATION_UPDATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Activate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oZT0Header&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0_NOME"&lt;/span&gt;  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;VldData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CommitData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  DELETE /microblog/v2/perfis/{perfilId}
&lt;/h2&gt;

&lt;p&gt;Assim como na operação &lt;code&gt;PUT&lt;/code&gt; nada novo é adicionado nos comandos do modelo, somente o tipo de operação indicada no método &lt;code&gt;Activate&lt;/code&gt;. Os principais comandos em Advpl que suportam o &lt;code&gt;DELETE&lt;/code&gt; na classe Rest estão a seguir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;lDelete&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbSeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xFilial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MODEL_OPERATION_DELETE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Activate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;VldData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CommitData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusão
&lt;/h1&gt;

&lt;p&gt;O código mudou o resultado api e classe? não. Os formatos de entrada e resposta continuaram os mesmos.&lt;br&gt;
Os ganhos de usar o modelo é não repetir validações e principalmente não fazer acesso direto às tabelas para recuperar conteúdo. É uma versão ideal para um serviço rest? Bem, não exatamente. Existem tópicos a serem melhorados e o principal é ter uma abstração receba os dados da api e só se comunique com o modelo e a resposta dessa abstração vai depois para o método que atendeu à requisição, algo a ser abordado numa das publicações futuras.&lt;br&gt;
É possível conferir o código feito exclusivamente para publicação neste &lt;a href="https://github.com/josimar-jr/microblog-protheus/pull/2"&gt;link&lt;/a&gt;.&lt;br&gt;
A próxima etapa será implementar recursos como paginação e ordem na recuperação de lista dos itens &lt;code&gt;GET&lt;/code&gt; geral.&lt;/p&gt;

</description>
      <category>advpl</category>
      <category>mvc</category>
      <category>rest</category>
      <category>api</category>
    </item>
    <item>
      <title>Um microblog usando Protheus - Rest Server, parte 3, serviço padrão rest de modelos mvc</title>
      <dc:creator>Josimar Junior</dc:creator>
      <pubDate>Thu, 03 Dec 2020 00:53:49 +0000</pubDate>
      <link>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-3-1j2k</link>
      <guid>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-3-1j2k</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Nesta parte será apresentado o serviço de rest padrão que é oferecido quando utilizado MVC.&lt;br&gt;
Para um bom entendimento de como funciona é importante que a pessoa esteja familiarizada com a construção de modelos de dados para MVC.&lt;br&gt;
O conteúdo disponível oficialmente sobre MVC está no &lt;a href="https://tdn.totvs.com/display/public/PROT/AdvPl+utilizando+MVC"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Essa parte é continuação da anterior e portanto caso tenha chegado até aqui sem ler a parte anterior, sugiro olhar ao menos a estrutura da tabela ZT0 - Perfis.&lt;br&gt;
&lt;a href="https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-2-1bch"&gt;Segunda parte&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  A construção do modelo de dados
&lt;/h1&gt;

&lt;p&gt;O modelo de dados para este caso é bem simples, como a tabela possui poucos campos e ainda não foi adicionada validação alguma, somente recuperar a estrutura e definir os ids para os componentes é exigido.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;ModelDdef&lt;/code&gt; ficou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;ModelDef&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;   &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;oStrZT0&lt;/span&gt;  &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;

    &lt;span class="n"&gt;oStrZT0&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;FWFormStruct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;oModel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;MpFormModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZMBMODEL"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;AddFields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0_FIELDS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oStrZT0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cadastro de perfis"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;oModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;GetModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0_FIELDS"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Perfis"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;oModel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os detalhes importantes neste modelo são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;as descrições para o modelo completo e para o cabeçalho/enchoice;&lt;/li&gt;
&lt;li&gt;o id como &lt;code&gt;ZMBMODEL&lt;/code&gt;, este id define qual o nome da função de usuário para os ponto de entradas que este modelo vai invocar e portanto, colocar com o mesmo nome do fonte faria acontecer alguns comportamentos inusitados (menu não aparecer, programa travar, erro durante carga, etc). Com o que foi definido nesse modelo os ponto de entradas serão encontrados pela função &lt;code&gt;U_ZMBMODEL&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Só com a definição do modelo não acontece a publicação do serviço rest do MVC, para isso é necessário adicionar os comandos &lt;code&gt;PUBLISH USER MODEL&lt;/code&gt; ou &lt;code&gt;PUBLISH MODEL&lt;/code&gt;, respectivamente para funções de usuário e funções do padrão.&lt;/p&gt;

&lt;p&gt;A documentação sobre os recursos oferecidos quando estes comandos são adicionados a fontes compilados estão descritos nessas documentações.&lt;br&gt;
&lt;a href="https://tdn.totvs.com/display/framework/4.+Publicando+o+REST+do+Model"&gt;Publicando um modelo como rest&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tdn.totvs.com/display/public/PROT/FWRestModel"&gt;FwRestModel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nesta publicação não será explicado o modelo mais avançado indicado pela segundo documentação, contudo serão explicadas as possibilidades criadas com esta forma avançada.&lt;br&gt;
Dica: modelos que possuem "condições" para a montagem de sua estrutura têm grandes chances de sofrer com comportamentos inadequados e erros, pois as threads para resposta dos serviços de rest raramente têm as mesmas variáveis públicas preenchidas quando comparadas com a execução por tela/smartclient, por isso evite condições na montagem do seu modelo de dados.&lt;/p&gt;
&lt;h1&gt;
  
  
  Fazendo a publicação de um modelo
&lt;/h1&gt;

&lt;p&gt;Para o modelo MVC do cadastro de Perfis foi realizada duas publicações de serviços: uma com o id &lt;code&gt;perfis&lt;/code&gt; e outra com o id &lt;code&gt;ZMBA010&lt;/code&gt;.&lt;br&gt;
Os comandos que fizeram estas publicações foram:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// http://localhost:18085/rest/fwmodel/Perfis/&lt;/span&gt;
&lt;span class="n"&gt;PUBLISH&lt;/span&gt; &lt;span class="n"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="n"&gt;REST&lt;/span&gt; &lt;span class="n"&gt;NAME&lt;/span&gt; &lt;span class="n"&gt;Perfis&lt;/span&gt; &lt;span class="n"&gt;SOURCE&lt;/span&gt; &lt;span class="n"&gt;ZMBA010&lt;/span&gt;

&lt;span class="c1"&gt;// http://localhost:18085/rest/fwmodel/ZMBA010/&lt;/span&gt;
&lt;span class="n"&gt;PUBLISH&lt;/span&gt; &lt;span class="n"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="n"&gt;REST&lt;/span&gt; &lt;span class="n"&gt;NAME&lt;/span&gt; &lt;span class="n"&gt;ZMBA010&lt;/span&gt; &lt;span class="n"&gt;SOURCE&lt;/span&gt; &lt;span class="n"&gt;ZMBA010&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após a compilação do arquivo com estas instruções e o ambiente configurado para atender a requisições REST, fica disponível na URI &lt;code&gt;.../fwmodel/ZMBA010/{chave}&lt;/code&gt; a recuperação de dados e informações sobre o cadastro MVC.&lt;br&gt;
Essa URI é a padrão para qualquer programa, portanto qualquer programa que teve seu modelo publicado ficará acessível a partir da URI &lt;code&gt;/fwmodel/{programa}/{chave}&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Explorando o modelo exposto
&lt;/h1&gt;

&lt;p&gt;Três endpoints são disponibilizados para permitir a leitura e análise de informações sobre o modelo publicado.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/schema&lt;/code&gt; - retorna a documentação da estrutura dos campos que inclui o nome, o tipo, o tamanho, etc. Traz bastante informação sobre o modelo de dados.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/xmldata&lt;/code&gt; - retorna a estrutura de um item para ser utilizado posteriormente nas operações de &lt;code&gt;POST&lt;/code&gt; e &lt;code&gt;PUT&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ZMBMODEL&lt;/span&gt; &lt;span class="na"&gt;Operation=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.01"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ZT0_FIELDS&lt;/span&gt; &lt;span class="na"&gt;modeltype=&lt;/span&gt;&lt;span class="s"&gt;"FIELDS"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ZT0_FILIAL&lt;/span&gt; &lt;span class="na"&gt;order=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ZT0_FILIAL&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ZT0_USRID&lt;/span&gt; &lt;span class="na"&gt;order=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ZT0_USRID&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ZT0_EMAIL&lt;/span&gt; &lt;span class="na"&gt;order=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ZT0_EMAIL&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ZT0_NOME&lt;/span&gt; &lt;span class="na"&gt;order=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ZT0_NOME&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ZT0_FIELDS&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ZMBMODEL&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/xmldatadetail&lt;/code&gt; - retorna a estrutura de um item (como o anterior) e com detalhes adicionais como tamanho, tipo do dado, título e obrigatoriedade.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ZMBMODEL&lt;/span&gt; &lt;span class="na"&gt;Operation=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.01"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ZT0_FIELDS&lt;/span&gt; &lt;span class="na"&gt;modeltype=&lt;/span&gt;&lt;span class="s"&gt;"FIELDS"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ZT0_FILIAL&lt;/span&gt; &lt;span class="na"&gt;order=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;len=&lt;/span&gt;&lt;span class="s"&gt;"2,0"&lt;/span&gt; &lt;span class="na"&gt;datatype=&lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="na"&gt;info=&lt;/span&gt;&lt;span class="s"&gt;"Filial"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ZT0_FILIAL&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ZT0_USRID&lt;/span&gt; &lt;span class="na"&gt;order=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;len=&lt;/span&gt;&lt;span class="s"&gt;"6,0"&lt;/span&gt; &lt;span class="na"&gt;datatype=&lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="na"&gt;info=&lt;/span&gt;&lt;span class="s"&gt;"cod usuário"&lt;/span&gt; &lt;span class="na"&gt;obrigat=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ZT0_USRID&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ZT0_EMAIL&lt;/span&gt; &lt;span class="na"&gt;order=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt; &lt;span class="na"&gt;len=&lt;/span&gt;&lt;span class="s"&gt;"100,0"&lt;/span&gt; &lt;span class="na"&gt;datatype=&lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="na"&gt;info=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;obrigat=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ZT0_EMAIL&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ZT0_NOME&lt;/span&gt; &lt;span class="na"&gt;order=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt; &lt;span class="na"&gt;len=&lt;/span&gt;&lt;span class="s"&gt;"100,0"&lt;/span&gt; &lt;span class="na"&gt;datatype=&lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="na"&gt;info=&lt;/span&gt;&lt;span class="s"&gt;"nome"&lt;/span&gt; &lt;span class="na"&gt;obrigat=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ZT0_NOME&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ZT0_FIELDS&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ZMBMODEL&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estes endpoints somente retornam no formato &lt;code&gt;application/xml&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Recuperando dados usando o modelo
&lt;/h1&gt;

&lt;p&gt;Os métodos e operações permitidos estão na tabela a seguir.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;método&lt;/th&gt;
&lt;th&gt;path&lt;/th&gt;
&lt;th&gt;objetivo&lt;/th&gt;
&lt;th&gt;usa informação do...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/fwmodel/Perfis/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;incluir um registro&lt;/td&gt;
&lt;td&gt;body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/fwmodel/Perfis/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;incluir um registro&lt;/td&gt;
&lt;td&gt;parâmetros de query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/fwmodel/Perfis/{pk}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;incluir um registro&lt;/td&gt;
&lt;td&gt;parâmetros de query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PUT&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/fwmodel/Perfis/{pk}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;incluir um registro&lt;/td&gt;
&lt;td&gt;body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/fwmodel/Perfis/{pk}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;incluir um registro&lt;/td&gt;
&lt;td&gt;nenhum&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Estas são exatamente as mesmas operações que foram feitas na parte anterior, contudo não foi feita a criação de uma classe Rest para responder a estas requisições e sim utilizado um modelo mvc para lidar com o cadastro na sua forma padrão.&lt;/p&gt;

&lt;p&gt;Estes endpoints e métodos respondem por padrão como &lt;code&gt;Content-Type: application/json&lt;/code&gt;, sendo possível também receber no formato &lt;code&gt;application/xml&lt;/code&gt; e para isso faça a requisição informando no header a chave &lt;code&gt;Accept: application/xml; charset=utf-8&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Os exemplos de como usar os endpoints estão na coleção do postman no &lt;a href="https://github.com/josimar-jr/microblog-protheus/tree/main/resources/postman"&gt;repositório&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Detalhes da api
&lt;/h1&gt;

&lt;p&gt;A principal diferença para o serviço construído antes são as novas possibilidades que a publicação do padrão permite.&lt;/p&gt;

&lt;p&gt;Na listagem dos itens é possível utilizar parâmetros de query que otimizam a busca permitindo recuperar somente os campos desejados e também controlar a paginação do itens.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;paginação: combinando as propriedades &lt;code&gt;count&lt;/code&gt; e &lt;code&gt;startindex&lt;/code&gt; é possível fazer a paginação, um exemplo é a expressão &lt;code&gt;/fwmodel/zmba010?count=20&amp;amp;startindex=2&lt;/code&gt; que traria os registros de &lt;code&gt;21 a 40&lt;/code&gt; conforme a ordem usada no modelo (normalmente a ordem de índice 1).&lt;/li&gt;
&lt;li&gt;filtragem: com a propriedade &lt;code&gt;filter&lt;/code&gt; é possível determinar uma expressão que irá restringir o resultado, como &lt;code&gt;filter=ZT0_ADMIN = 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;restrição de campos: com a propriedade &lt;code&gt;fields&lt;/code&gt; é possível reduzir a quantidade de campos retornados, de forma a otimizar o tempo de resposta e ocupação de banda na rede, a expressão &lt;code&gt;fields=ZT0_USRID,ZT0_NOME&lt;/code&gt; faria retornar somente os campos &lt;code&gt;ZT0_USRID&lt;/code&gt; e &lt;code&gt;ZT0_NOME&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ter estas funcionalidades somente com a construção do modelo de dados MVC é um ganho imenso e portanto, no advento de não ter muito tempo para desenvolver uma api ou não querer deixar a api muito simples (como a da parte anterior), publicar um modelo é uma excelente saída. A desvantagem está no fato dos nomes dos campos serem as propriedades e com isso obrigar os clientes das apis lidarem com coisas que podem não fazer sentido nenhum para a aplicação cliente.&lt;/p&gt;

&lt;h1&gt;
  
  
  O modelo avançado
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://tdn.totvs.com/display/public/PROT/FWRestModel"&gt;Nessa documentação já citada&lt;/a&gt; existe um recurso não utilizado na publicação do modelo para Perfis.&lt;br&gt;
A opção &lt;code&gt;RESOURCE OBJECT &amp;lt;objeto&amp;gt;&lt;/code&gt; permite determinar qual a classe fará uma parte da interpretação dos comandos entre o modelo (que possui os dados) e o fwmodel (que responde à requisição). &lt;br&gt;
Tendo o controle dessa camada intermediária é possível implementar mais parâmetros de query e estender comportamentos, como permitir a definição de ordem dos dados na listagem geral que não é permitida por padrão.&lt;br&gt;
Na documentação tem o fonte &lt;code&gt;FWRestModelObject.prx&lt;/code&gt; com uma implementação bem similar a do padrão e um exemplo com a implementação simulada para um serviço de filiais.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusão
&lt;/h1&gt;

&lt;p&gt;Este é um tópico em que é importante utilizar a coleção do postman e os endpoints para ver as coisas acontecerem no sistema.&lt;br&gt;
Muito é oferecido somente com a publicação do modelo e cadastros simples são bem atendidas somente com isso.&lt;br&gt;
Não será feito uso deste formato de api no microblog usando o Protheus e este formato foi demonstrado aqui para deixar explícita uma das possibilidades.&lt;br&gt;
A próxima publicação será sobre usar o modelo MVC para lidar com as operações de Criação, Atualização, Exclusão e Leitura no banco de dados ao invés de fazer estas operações diretamente com &lt;code&gt;Reclock&lt;/code&gt; ou &lt;code&gt;Insert&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>advpl</category>
      <category>rest</category>
      <category>mvc</category>
      <category>api</category>
    </item>
    <item>
      <title>Um microblog usando Protheus - Rest Server, parte 2, classe para serviço básico</title>
      <dc:creator>Josimar Junior</dc:creator>
      <pubDate>Sun, 29 Nov 2020 23:06:20 +0000</pubDate>
      <link>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-2-1bch</link>
      <guid>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-2-1bch</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Na &lt;a href="https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-1-5999"&gt;primeira parte&lt;/a&gt; foi dito sobre o que seria construído e o que seria abordado e explicado nessa série de publicações.&lt;br&gt;
Essa será a primeira publicação que conterá código e informações sobre a configuração do ambiente e o modus operandi para a construção do microblog.&lt;br&gt;
Para o melhor aproveitamento nesta publicação é esperado a pessoa lendo tenha uma compreensão razoável de como o Protheus funciona com relação aos dicionários e tabelas/aliases, assim como entendimento intermediário sobre linguagem de programação Advpl.&lt;br&gt;
Algumas definições e conceitos podem ter links de documentação e espero conseguir prover o máximo dessas referências para ajudar.&lt;/p&gt;
&lt;h1&gt;
  
  
  Ambiente
&lt;/h1&gt;

&lt;p&gt;O ambiente é o Protheus release 12.1.27 expedido em Outubro com os binários DbAccess, Appserver e Smarclient e a lib também expedidos junto com essa release. Portanto para replicar o ambiente de desenvolvimento pode-se iniciar uma base e seguir os passos com os recursos utilizados e mencionados no decorrer das publicações ou utilizar o arquivo de backup mencionado no repositório do Github com a construção do &lt;a href="https://github.com/josimar-jr/microblog-protheus"&gt;microblog&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Estrutura de tabelas
&lt;/h1&gt;

&lt;p&gt;Para a construção dos recursos do microblog foram criadas três tabelas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ZT0: conterá informações relacionadas com os perfis;&lt;/li&gt;
&lt;li&gt;ZT1: conterá informações sobre as publicações e comentários e;&lt;/li&gt;
&lt;li&gt;ZT2: conterá informações sobre os perfis que seguem uns aos outros.
Os dicionários de tabelas (SX2), índices (SIX) e campos (SX3) estão disponíveis na forma de arquivos .dtc no repositório do microblog para a consulta e réplica da configuração das tabelas, contudo não há segredo e um diagrama simplificado dos relacionamentos é exibido a seguir.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DQjDPX3R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fgh964i1wumhumj5n9h4.jpg" alt="Diagrama indicando os campos e relacionamentos das tabelas ZT0, ZT1 e ZT2"&gt;
Com o diagrama é possível perceber que poucas regras serão aplicadas contudo, é seguro dizer que serão regras e validações o suficiente para entender onde melhor aplicá-las quando respondendo à requisições por api.
O diagrama simplificado mostra os relacionamentos da tabela de Perfis (ZT0) com as Publicações (ZT1) e com a tabela que guardará os Perfis seguidores e seguidos (ZT2).
O principal campo utilizado para relacionamento nessas tabelas é o ZT0_USRID, este será o id de um usuário do Protheus, sim um usuário do sistema. O principal motivo para utilizar um usuário do sistema é conseguir com a combinação de email (ou id) e senha realizar a autenticação no sistema (login no Protheus).
Além deste campo como chave, a tabela de Publicações tem o próprio campo chave ZT1_ID que terá um valor aleatório sendo gerado e conferido para não existir conflitos na base e a última tabela tem um chave composta por id de usuário seguidor e id de usuário seguido.
Essa é a estrutura de tabelas que conterá as principais operações e apoiará a construção do microblog.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Configuração do servidoe de Rest Protheus
&lt;/h1&gt;

&lt;p&gt;Os detalhes de configuração podem ser conseguidos em um dos links mencionados no tópico anterior, que é esta &lt;a href="https://tdn.totvs.com/pages/viewpage.action?pageId=185747842"&gt;documentação aqui&lt;/a&gt;.&lt;br&gt;
As seções que vou destacar a importância são:&lt;br&gt;
&lt;code&gt;[HTTPREST]&lt;/code&gt;: aqui é determinado qual ips/dns o Appserver irá ouvir e aguardar pelas requisições.&lt;br&gt;
Nesta série de publicações é utilizada a seguinte configuração:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;; REST CONFIG
&lt;/span&gt;&lt;span class="nn"&gt;[HTTPV11]&lt;/span&gt;
&lt;span class="py"&gt;ENABLE&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;
&lt;span class="py"&gt;SOCKETS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;HTTPREST&lt;/span&gt;
&lt;span class="c"&gt;; ADVPL=1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SOCKETS=HTTPREST&lt;/code&gt; =&amp;gt; determina qual a seção seguinte para as demais configurações que neste caso será a seção &lt;code&gt;[HTTPREST]&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ADVPL=1&lt;/code&gt; =&amp;gt; determina qual modelo de accept de requisições será utilizado &lt;code&gt;1&lt;/code&gt; é o Advpl e &lt;code&gt;0&lt;/code&gt; é o misto de TLPP com binário. Neste caso a chave está comentada e portanto deixará o que produto decidir usar, que por enquanto é o modelo Advpl. Mais detalhes dessa configuração veja este &lt;a href="https://tdn.totvs.com/display/framework/Entendendo+as+novidades+do+REST"&gt;artigo&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[HTTPREST]&lt;/span&gt;
&lt;span class="py"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;18085&lt;/span&gt;
&lt;span class="py"&gt;URIS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;URI&lt;/span&gt;
&lt;span class="py"&gt;SECURITY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na configuração para o microblog foi definida a porta como 18085 (com a chave &lt;code&gt;PORT=18085&lt;/code&gt;) e habilitada a segurança no servidor Rest (com a chave SECURITY=1), com isso as requisições por padrão estão "seguras" e exigem que seja provido algum tipo de autenticação para que a resposta aconteça.&lt;br&gt;
A chave &lt;code&gt;URIS=URI&lt;/code&gt; define qual URLs vão ser estabelecidas como path raíz para a montagem das URLs/paths dos métodos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[URI]&lt;/span&gt;
&lt;span class="py"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/rest&lt;/span&gt;
&lt;span class="py"&gt;PREPAREIN&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;99,01&lt;/span&gt;
&lt;span class="py"&gt;INSTANCES&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1,2,1,1&lt;/span&gt;
&lt;span class="py"&gt;CORSENABLE&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;
&lt;span class="py"&gt;ALLOWORIGIN&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;
&lt;span class="py"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;p12microblog&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa é a seção que possui a maior quantidade de configurações e onde boa parte dos problemas de configuração surgem, portanto item a item será explicado.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;URL=/rest&lt;/code&gt; =&amp;gt; indica o começo da URL que o servidor irá aguarda e responder às requisições. Pode ser configurado com &lt;code&gt;/&lt;/code&gt; e portanto logo após a raiz será o path para o método/classe. Aqui foi configurado como &lt;code&gt;/rest&lt;/code&gt; pelo hábito. Este é o endereço que a página com a lista de serviços é exibida e pode ser consultada.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PREPAREIN=99,01&lt;/code&gt; =&amp;gt; determina o grupo de empresa e filial que as threads para resposta terão o ambiente preparado. Caso a empresa seja diferente de &lt;code&gt;99&lt;/code&gt; garanta que tenha licenças o suficiente para a preparação destes ambientes. É possível também definir como &lt;code&gt;ALL&lt;/code&gt; contudo isso traz uma necessidade das requisições começarem a incluir o header &lt;code&gt;tenantid: 99,01&lt;/code&gt; para que seja possível determinar qual o grupo e filial responsável por responder a requisição, quando acontece de ter a configuração como &lt;code&gt;ALL&lt;/code&gt; e não é informado o &lt;code&gt;tenantid&lt;/code&gt; na requisição, qualquer thread poderá responder e com isso a primeira thread livre é que fará a resposta. Em situações de negócio, quando filial já é determinante para encontrar registros, ter a resposta acontecendo ao "acaso" considerando grupo e filial, definitivamente não é um risco que vale correr.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;INSTANCES=1,2,1,1&lt;/code&gt; =&amp;gt; aqui são indicados o limite inferior e superior de threads para responder às requisições. Os últimos dois parâmetros indicam a quantidade para tentar deixar livre e quantidade para incrementar quando necessário. Um exemplo onde é possível explicar melhor é &lt;code&gt;10,50,2,5&lt;/code&gt; que significa suba imediatamente &lt;code&gt;10&lt;/code&gt; threads, pode subir até &lt;code&gt;50&lt;/code&gt; threads, tente deixar &lt;code&gt;2&lt;/code&gt; threads livres e quando não conseguir prepare &lt;code&gt;5&lt;/code&gt; novas threads.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CORSENABLE=1&lt;/code&gt; =&amp;gt; essa é a configuração que permite aplicações clientes do rest server exibir conteúdo respondido pelo Rest Advpl nos navegadores. Essa chave é essencial para aplicações Angular, React ou Vuejs que façam requisições ao servidor Protheus.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ALLOWORIGIN=*&lt;/code&gt; =&amp;gt; configuração adicional à chave &lt;code&gt;CORSENABLE&lt;/code&gt; aqui são indicados quais os hosts (ip ou dns do servidores) podem exibir o conteúdo respondido. O valor &lt;code&gt;*&lt;/code&gt; determina que pode ser exibido por qualquer endereço, contudo uma configuração útil de exemplo é &lt;code&gt;ALLOWORIGIN=meuapp.company.com,appxyz.serverabc.com.br&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ENVIRONMENT=p12microblog&lt;/code&gt; =&amp;gt; chave que indica qual o ambiente terá as threads preparadas. Este é outro elemento comum de problemas na configuração, pois eventuais problemas no ambiente indicado aqui (como acessos de usuários, limitação de licenças e uso simultâneo por Smartclient) afetarão a execução dos métodos e classes rest no Protheus.
A imagem a seguir mostra como verificar se a configuração inicial está correta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---OndNCdM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yctcusgnwzik1nnel8kx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---OndNCdM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yctcusgnwzik1nnel8kx.jpg" alt="Página com os serviços rest disponíveis para serem utilizados"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Escrevendo os serviços
&lt;/h1&gt;

&lt;p&gt;Este é o primeiro serviço sendo escrito e portanto terá a maior quantidade de detalhes oferecidos, os demais irão se basear na explicação contida nos próximos parágrafos.&lt;br&gt;
Os arquivos de header exigidos para a compilação do arquivo &lt;code&gt;.prw&lt;/code&gt; com a classe para o serviço rest são:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include "protheus.ch"
#include "restful.ch"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Definição da classe
&lt;/h2&gt;

&lt;p&gt;A indicação do nome da classe &lt;code&gt;Perfis&lt;/code&gt; e qual a descrição para exibição na página de serviços.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsrestful&lt;/span&gt; &lt;span class="n"&gt;Perfis&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;"Trata a atualização dos perfis que usam o microblog"&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="n"&gt;wsrestful&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A definição das propriedades na classe &lt;code&gt;Perfil&lt;/code&gt; que serão preenchidas e podem ser utilizadas para a montagem da resposta. Essas propriedades serão preenchidas quando vierem elementos com o mesmo nome como parâmetros de path e query ou no header da requisição, os listados a seguir serão exemplos nos parâmetros de path e query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;    &lt;span class="n"&gt;wsdata&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt;         &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="n"&gt;optional&lt;/span&gt;
    &lt;span class="n"&gt;wsdata&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;             &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="n"&gt;optional&lt;/span&gt;
    &lt;span class="n"&gt;wsdata&lt;/span&gt; &lt;span class="n"&gt;perfilId&lt;/span&gt;         &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt; &lt;span class="n"&gt;optional&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na construção acima as propriedades são opcionais e portanto caso não estejam presentes a execução não é interrompida ainda na camada de framework. É importante definir o tipo de dado para que não seja exigido a checagem ou conversão na camada de resposta, os tipos disponíveis são .&lt;br&gt;
As definições dos métodos que irão responder para a URL &lt;code&gt;host:port/rest/microblog/v1/perfis&lt;/code&gt; quando &lt;code&gt;GET&lt;/code&gt; ou &lt;code&gt;POST&lt;/code&gt; acontece da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;    &lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;GET&lt;/span&gt; &lt;span class="n"&gt;V1ALL&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;"Recupera todos os perfis"&lt;/span&gt; &lt;span class="n"&gt;wssyntax&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis"&lt;/span&gt;
    &lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="n"&gt;V1ROOT&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;"Cria um perfil para o microblog"&lt;/span&gt; &lt;span class="n"&gt;wssyntax&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os valores &lt;code&gt;GET V1ALL&lt;/code&gt; e &lt;code&gt;POST V1ROOT&lt;/code&gt; associados com &lt;code&gt;wsmethod&lt;/code&gt; são as identificações dos métodos construídos para responder a requisição. A marcação &lt;code&gt;wssyntax&lt;/code&gt; estabelece a URI que ficará visível na página de serviços e a marcação &lt;code&gt;path&lt;/code&gt; estabelece o endereço de URI que o método responderá.&lt;br&gt;
Os métodos de HTTP fazem parte da identificação do método e portanto não é possível fazer um http &lt;code&gt;POST&lt;/code&gt; ser respondido pelo método &lt;code&gt;GET XYZ&lt;/code&gt;.&lt;br&gt;
As definições dos métodos que irão responder para a URL &lt;code&gt;host:port/rest/microblog/v1/perfis/{perfilId}&lt;/code&gt; quando &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt; ou &lt;code&gt;DELETE&lt;/code&gt; são:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;    &lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;GET&lt;/span&gt; &lt;span class="n"&gt;V1ID&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;"Recupera um perfil pelo id"&lt;/span&gt; &lt;span class="n"&gt;wssyntax&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis/{perfilId}"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis/{perfilId}"&lt;/span&gt;
    &lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;PUT&lt;/span&gt; &lt;span class="n"&gt;V1ID&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;"Faz a atualização de um perfil"&lt;/span&gt; &lt;span class="n"&gt;wssyntax&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis/{perfilId}"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis/{perfilId}"&lt;/span&gt;
    &lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;DELETE&lt;/span&gt; &lt;span class="n"&gt;V1&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s"&gt;"Faz a exclusão de um perfil"&lt;/span&gt; &lt;span class="n"&gt;wssyntax&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis/{perfilId}"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s"&gt;"/microblog/v1/perfis/{perfilId}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O quê há de diferente com os primeiros métodos? A identificação dos verbos http e a inclusão da expressão &lt;code&gt;/{perfilId}&lt;/code&gt; nos paths e isso define limites e comportamentos importantes. A primeira coisa é que esta expressão faz com que uma requisição como &lt;code&gt;GET /rest/microblog/v1/perfis/xxx001&lt;/code&gt; seja respondida pelo método &lt;code&gt;GET V1ID&lt;/code&gt; e não pelo método &lt;code&gt;GET V1ALL&lt;/code&gt;. A segunda é que o valor da propriedade &lt;code&gt;perfilId&lt;/code&gt; será &lt;code&gt;xxx001&lt;/code&gt;.&lt;br&gt;
Estas são as definições dos métodos e URIs que serão respondidas por esta classe.&lt;br&gt;
As boas práticas envolvidas até aqui foram:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;definir versionamento no path/uri: é um formato que possui contestações, contudo é mais simples de perceber qual o serviço/método/classe/assinatura devem ser utilizados.&lt;/li&gt;
&lt;li&gt;incluir o nome da classe no path: neste exemplo a classe é &lt;code&gt;Perfis&lt;/code&gt; e faz parte da combinação de agrupador de path escolhido &lt;code&gt;microblog/v1/perfis&lt;/code&gt;.
## Definição dos métodos
A seguir a implementação dos métodos são mostradas e os comandos relacionados com o rest são explicados.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  POST - inclui um item
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="n"&gt;V1ROOT&lt;/span&gt; &lt;span class="n"&gt;wsservice&lt;/span&gt; &lt;span class="n"&gt;Perfis&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;logical&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;      &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;  &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;

    &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetContentType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;jBody&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;FromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;GetContent&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="n"&gt;jResponse&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Nil&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Nil&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"body_invalido"&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Forneça as propriedades 'email', 'user_id' e 'name' no body"&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;SetRestFault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;DBSelectArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;Reclock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;
            &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_FILIAL&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;xFilial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_EMAIL&lt;/span&gt;  &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_USRID&lt;/span&gt;  &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_NOME&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MsUnlock&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_EMAIL&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_USRID&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_NOME&lt;/span&gt;
        &lt;span class="c1"&gt;// jResponse["inserted_at"] := ZT0-&amp;gt;S_T_A_M_P_&lt;/span&gt;
        &lt;span class="c1"&gt;// jResponse["updated_at"] := ZT0-&amp;gt;I_N_S_D_T_&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste método o objetivo é recuperar o conteúdo enviado no body pela requisição e criar um registro na tabela quando o conteúdo é válido. Os trechos relacionados com rest em Advpl são:&lt;br&gt;
&lt;code&gt;wsmethod POST V1ROOT wsservice Perfis&lt;/code&gt; =&amp;gt; indicação do corpo do método definido anteriormente na classe.&lt;br&gt;
&lt;code&gt;self:SetContentType("application/json")&lt;/code&gt; =&amp;gt; define que a resposta terá o conteúdo como &lt;code&gt;application/json&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;jBody:FromJson(self:GetContent())&lt;/code&gt; =&amp;gt; preenche a variável &lt;code&gt;jBody&lt;/code&gt; com o conteúdo recebido no body da requisição.&lt;br&gt;
&lt;code&gt;if (jBody["email"] == Nil .Or. jBody["user_id"] == Nil .Or. jBody["name"] == Nil)&lt;/code&gt; =&amp;gt; forma com que os conteúdos das propriedades no body estão sendo validados, quando alguma destes valores não foi informado é considerada uma requisição inválida.&lt;br&gt;
&lt;code&gt;self:SetResponse(jResponse:ToJson())&lt;/code&gt; =&amp;gt; definição da resposta quando percebido erro no body.&lt;br&gt;
&lt;code&gt;SetRestFault(400, jResponse:ToJson(), , 400)&lt;/code&gt; =&amp;gt; definição do status HTTP de erro da requisição.&lt;br&gt;
&lt;code&gt;jResponse["email"]   := ZT0-&amp;gt;ZT0_EMAIL&lt;/code&gt; =&amp;gt; montagem do json de resposta à requisição quando há sucesso na operação. A atribuição é repetida para as outras propriedades do json de resposta.&lt;br&gt;
&lt;code&gt;self:SetResponse(jResponse:ToJson())&lt;/code&gt; =&amp;gt; define a resposta que deve acontecer.&lt;br&gt;
&lt;code&gt;return lProcessed&lt;/code&gt; =&amp;gt; indica se o processamento aconteceu com sucesso ou com erro/falha, isso indicará se o &lt;code&gt;status HTTP&lt;/code&gt; definido pela função &lt;code&gt;SetRestFault&lt;/code&gt; deve ser considerado. Neste exemplo quando um body é inválido (por exemplo não contém a propriedade &lt;code&gt;email&lt;/code&gt;) é retornado status HTTP &lt;code&gt;400&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  GET geral - retorna uma lista
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;GET&lt;/span&gt; &lt;span class="n"&gt;V1ALL&lt;/span&gt; &lt;span class="n"&gt;wsreceive&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="n"&gt;wsservice&lt;/span&gt; &lt;span class="n"&gt;Perfis&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;logical&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;  &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;jTempItem&lt;/span&gt;  &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
    &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="c1"&gt;// Define o tipo de retorno do método&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetContentType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// As propriedades da classe receberão os valores enviados por querystring&lt;/span&gt;
    &lt;span class="c1"&gt;// exemplo: http://localhost:18085/rest/microblog/v1/perfis?page=1&amp;amp;pageSize=5&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

    &lt;span class="n"&gt;DbSelectArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;DbSetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ZT0_FILIAL+ZT0_NOME&lt;/span&gt;
    &lt;span class="n"&gt;DbSeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xFilial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;// exemplo de retorno de uma lista de objetos JSON&lt;/span&gt;
    &lt;span class="n"&gt;jResponse&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;aAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;jTempItem&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aTail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="n"&gt;jTempItem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_EMAIL&lt;/span&gt;
        &lt;span class="n"&gt;jTempItem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_USRID&lt;/span&gt;
        &lt;span class="n"&gt;jTempItem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_NOME&lt;/span&gt;
        &lt;span class="c1"&gt;// jTempItem["inserted_at"] := ZT0-&amp;gt;S_T_A_M_P_&lt;/span&gt;
        &lt;span class="c1"&gt;// jTempItem["updated_at"] := ZT0-&amp;gt;I_N_S_D_T_&lt;/span&gt;
        &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbSkip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;wsreceive page, pageSize&lt;/code&gt; =&amp;gt; este trecho determina que as propriedades &lt;code&gt;page&lt;/code&gt; e &lt;code&gt;pageSize&lt;/code&gt; podem ser preenchidas com o conteúdo oferecido pelos parâmetros de path ou query. Neste caso são de query indicador por &lt;code&gt;?page=2&amp;amp;pageSize=15&lt;/code&gt; na montagem da URL requisitada.&lt;br&gt;
&lt;code&gt;default self:page := 1&lt;/code&gt; =&amp;gt; como parâmetros de query não são obrigatórios o default garante algum valor. Estes parâmetros somente serão usados em versões mais sofisticadas, pois seria complicado implementar paginação com esta versão simplificada do serviço rest em Advpl.&lt;br&gt;
&lt;code&gt;jResponse['items'] := {}&lt;/code&gt; =&amp;gt; a resposta ao serviço é uma lista então é definida a propriedade &lt;code&gt;items&lt;/code&gt; como &lt;code&gt;array&lt;/code&gt; em Advpl.&lt;br&gt;
&lt;code&gt;aAdd(jResponse['items'], JsonObject():New())&lt;/code&gt; =&amp;gt; um novo item é adicionado e recebe uma instância da classe &lt;a href="https://tdn.totvs.com/display/tec/Classe+JsonObject"&gt;&lt;code&gt;JsonObject&lt;/code&gt;&lt;/a&gt;. Com o JsonObject é possível montar json de forma simplificada.&lt;br&gt;
&lt;code&gt;jTempItem := aTail(jResponse['items'])&lt;/code&gt; =&amp;gt; recupera o último &lt;code&gt;item&lt;/code&gt; adicionado ao &lt;code&gt;array&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;jTempItem["email"]   := ZT0-&amp;gt;ZT0_EMAIL&lt;/code&gt; =&amp;gt; atribui as propriedades do item corrente ao json de resposta.&lt;br&gt;
&lt;code&gt;self:SetResponse(jResponse:ToJson())&lt;/code&gt; =&amp;gt; responde com a lista de itens recuperados da tabela ZT0.&lt;/p&gt;

&lt;h3&gt;
  
  
  GET um - retorna um item
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;GET&lt;/span&gt; &lt;span class="n"&gt;V1ID&lt;/span&gt; &lt;span class="n"&gt;pathparam&lt;/span&gt; &lt;span class="n"&gt;perfilId&lt;/span&gt; &lt;span class="n"&gt;wsservice&lt;/span&gt; &lt;span class="n"&gt;Perfis&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;logical&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;  &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;

    &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetContentType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;DbSelectArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;DbSetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ZT0_FILIAL+ZT0_USRID&lt;/span&gt;

    &lt;span class="n"&gt;jResponse&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Id não ser vazio e existir como item na tabela&lt;/span&gt;
    &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbSeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xFilial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;

        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_EMAIL&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_USRID&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_NOME&lt;/span&gt;
        &lt;span class="c1"&gt;// jResponse["inserted_at"] := ZT0-&amp;gt;S_T_A_M_P_&lt;/span&gt;
        &lt;span class="c1"&gt;// jResponse["updated_at"] := ZT0-&amp;gt;I_N_S_D_T_&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"id_invalido"&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Perfil não encontrado utilizando o #[id] informado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;SetRestFault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pathparam perfilId&lt;/code&gt; =&amp;gt; este trecho na indicação de início do corpo do método determina o preenchimento da propriedade &lt;code&gt;perfilId&lt;/code&gt; da classe &lt;code&gt;Perfil&lt;/code&gt;. O parâmetro de path é obrigatório e portanto é seguro fazer o uso da propriedade sem receios.&lt;br&gt;
&lt;code&gt;ZT0-&amp;gt;(DbSeek(xFilial("ZT0")+self:perfilId))&lt;/code&gt; =&amp;gt; este é um exemplo do uso da propriedade diretamente em uma pesquisa/posicionamento de registro na tabela ZT0.&lt;br&gt;
Essa foi a última particularidade relacionada com classes e métodos para serviços rest e montagem de respostas destes serviços.&lt;br&gt;
Os demais métodos não terão suas particularidades em puro Advpl comentadas.&lt;/p&gt;

&lt;h3&gt;
  
  
  PUT - altera um item e retorna este item
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;PUT&lt;/span&gt; &lt;span class="n"&gt;V1ID&lt;/span&gt; &lt;span class="n"&gt;pathparam&lt;/span&gt; &lt;span class="n"&gt;perfilId&lt;/span&gt; &lt;span class="n"&gt;wsservice&lt;/span&gt; &lt;span class="n"&gt;Perfis&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;logical&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;  &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;

    &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetContentType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;DbSelectArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;DbSetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ZT0_FILIAL+ZT0_USRID&lt;/span&gt;

    &lt;span class="n"&gt;jResponse&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Id não ser vazio e existir como item na tabela&lt;/span&gt;
    &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbSeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xFilial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;

        &lt;span class="n"&gt;jBody&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;FromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;GetContent&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"body_invalido"&lt;/span&gt;
            &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Forneça a propriedade 'name' no body"&lt;/span&gt;

            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="n"&gt;SetRestFault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;

            &lt;span class="n"&gt;Reclock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;
                &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_NOME&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jBody&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MsUnlock&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

            &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_EMAIL&lt;/span&gt;
            &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_USRID&lt;/span&gt;
            &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZT0_NOME&lt;/span&gt;
            &lt;span class="c1"&gt;// jResponse["inserted_at"] := ZT0-&amp;gt;S_T_A_M_P_&lt;/span&gt;
            &lt;span class="c1"&gt;// jResponse["updated_at"] := ZT0-&amp;gt;I_N_S_D_T_&lt;/span&gt;

            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;endif&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"id_invalido"&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Perfil não encontrado utilizando o #[id] informado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;SetRestFault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  DELETE - exclui um item
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;wsmethod&lt;/span&gt; &lt;span class="n"&gt;DELETE&lt;/span&gt; &lt;span class="n"&gt;V1&lt;/span&gt; &lt;span class="n"&gt;pathparam&lt;/span&gt; &lt;span class="n"&gt;perfilId&lt;/span&gt; &lt;span class="n"&gt;wsservice&lt;/span&gt; &lt;span class="n"&gt;Perfis&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;logical&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lDelete&lt;/span&gt;    &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;logical&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;  &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;

    &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetContentType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;DbSelectArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;DbSetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ZT0_FILIAL+ZT0_USRID&lt;/span&gt;

    &lt;span class="n"&gt;jResponse&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Id não ser vazio e existir como item na tabela&lt;/span&gt;
    &lt;span class="n"&gt;varinfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Alltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;

        &lt;span class="c1"&gt;// Se não encontrar o registro, não faz nada e retorna verdadeiro&lt;/span&gt;
        &lt;span class="n"&gt;lDelete&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbSeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xFilial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lDelete&lt;/span&gt;
            &lt;span class="n"&gt;Reclock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ZT0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;
                &lt;span class="n"&gt;DbDelete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;ZT0&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MsUnlock&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;endif&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"id_invalido"&lt;/span&gt;
        &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Perfil não encontrado utilizando o #[id] informado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perfilId&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SetResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;SetRestFault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jResponse&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;lProcessed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;endif&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lProcessed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A imagem a seguir mostra o serviço de Perfis na lista.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H-cHQ6fM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e3gd6ofddvddp6er95a5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H-cHQ6fM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e3gd6ofddvddp6er95a5.jpg" alt="Serviço de Perfis sendo exibido na lista de serviços Rest disponíveis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A imagem a seguir mostra os detalhes do serviço de Perfis.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VgWFVssj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xk31q9i7z3vuwyvlhwyd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VgWFVssj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xk31q9i7z3vuwyvlhwyd.jpg" alt="Métodos disponíveis no serviço de Perfis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusão
&lt;/h1&gt;

&lt;p&gt;Este é um modo de ter as operações básicas de CRUD acontecendo em determinada tabela do sistema Protheus usando serviços Rest.&lt;br&gt;
Essa implementação falha em diversos conceitos e técnicas para evitar duplicidade de código, organização e design de componentes internos e principalmente cria alto acoplamento entre ler e traduzir a requisição para uma entidade Perfil e gravar isso na tabela. Esse alto acoplamento não será endereçado tão logo.&lt;br&gt;
O próximo passo será mostrar como funciona a exposição de serviços rest quando utilizado modelos MVC e qual a diferença para o CRUD construído para a tabela ZT0.&lt;/p&gt;

</description>
      <category>protheus</category>
      <category>rest</category>
      <category>api</category>
      <category>advpl</category>
    </item>
    <item>
      <title>Um microblog usando Protheus - Rest Server, parte 1, o que será esta série</title>
      <dc:creator>Josimar Junior</dc:creator>
      <pubDate>Sun, 22 Nov 2020 18:20:56 +0000</pubDate>
      <link>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-1-5999</link>
      <guid>https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-1-5999</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Existem alguns conteúdos sobre o uso e criação de apis Rest usando o Protheus e a linguagem ADVPL, contudo pouco vai além da montagem básica dos métodos e operações padrões. Então, esta série tem o objetivo de fazer um microblog (aplicação tipo Twitter) usando o servidor Rest do Protheus com Advpl.&lt;br&gt;
Para criar a api usando Advpl será necessário discutir e explicar alguns conceitos de como o Rest funciona e eventuais particularidades quando comparado com as linguagens e frameworks de mercado.&lt;br&gt;
Alguns conteúdos com a documentação ou artigos com exemplos de uso são:&lt;br&gt;
link 1: &lt;a href="https://tdn.totvs.com/pages/viewpage.action?pageId=75268866"&gt;Web Services REST/Server&lt;/a&gt;&lt;br&gt;
link 2: &lt;a href="https://medium.com/totvsdevelopers/rest-no-protheus-b%C3%A1sico-do-b%C3%A1sico-a4b4431a4e3e"&gt;Exemplo simples&lt;/a&gt;&lt;br&gt;
link 3: &lt;a href="https://medium.com/@toledo.anderson/cria%C3%A7%C3%A3o-de-servi%C3%A7os-rest-no-protheus-utilizando-framework-bf758165fe5c"&gt;Exemplo mais complexo&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  O Rest no Protheus
&lt;/h1&gt;

&lt;p&gt;A sequência de artigos e documentação no link 1 acima aborda de forma bem abrangente o "como funciona" e portanto para mais detalhes sugiro a leitura daquela documentação com atenção.&lt;br&gt;
O Rest com Advpl no Protheus foi construído para suportar os seguintes métodos de REST sobre HTTP &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt; e &lt;code&gt;OPTIONS&lt;/code&gt;.&lt;br&gt;
A construção dos serviços segue um pouco do modelo das classes de serviços para &lt;code&gt;Web Services SOAP&lt;/code&gt; e portanto, em Advpl são construídas classes &lt;code&gt;WSRESTFUL&lt;/code&gt; e com isso alguns métodos dessas classes irão responder pelos métodos HTTP conforme a URI definida. Estes elementos serão detalhados quando os serviços começarem a ser construídos.&lt;br&gt;
A execução do Rest Server acontece em duas etapas: a recepção das requisições e validação de requisições e depois o processamento e resposta. Essa divisão é importante especialmente para entender o que pode ser melhorado com relação a tempo de resposta dos serviços. É possível observar estas etapas quando é ligado o log &lt;code&gt;FWTRACELOG=1&lt;/code&gt; na seção do ambiente configurado para o Rest Server.&lt;br&gt;
Estes são os elementos importantes no momento, caso tenha criado curiosidade sobre algum dos temas mencionados sugiro procurar ou praticar o que é mencionado nas publicações.&lt;br&gt;
Importante: será utilizado Advpl em boa parte dos exemplos e não TLPP, TLPP precisará da sua própria jornada e aplicação de exemplo. Sobre a diferença de Rest com Advpl e TLPP esta documentação é um excelente ponto de partida &lt;a href="https://tdn.totvs.com/display/framework/Entendendo+as+novidades+do+REST"&gt;Rest Advpl x Rest 2.0&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  O projeto do microblog
&lt;/h1&gt;

&lt;p&gt;Uma das maneiras para aprender e exercitar situações complexas no desenvolvimento é com a escolha de soluções para serem desenvolvidas. No passado para entender e aprender como criar, desenvolver e principalmente entender os conceitos de desenvolvimento web utilizei &lt;code&gt;Ruby on Rails&lt;/code&gt; e segui o &lt;a href="https://www.learnenough.com/ruby-on-rails-6th-edition-tutorial"&gt;Rails Tutorial&lt;/a&gt;.&lt;br&gt;
A aplicação desenvolvida é um clone do Twitter e com isso vários conceitos puderam ser abordados com relação ao construção da aplicação (CRUD simples, operações complexas, atualizações parciais e validações complexas, renderização de componentes, etc). Então utilizando como exemplo a aplicação do Rails Tutorial pensei em fazer o mesmo para apresentar a construção de uma Api Rest usando o Protheus.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que terá no projeto?
&lt;/h2&gt;

&lt;p&gt;O projeto irá conter duas entidades: Perfis e Publicações.&lt;br&gt;
Estas duas entidades depois irão se relacionar e as funcionalidades disponibilizadas ao final serão:&lt;br&gt;
login;&lt;br&gt;
criação, atualização e inativação de perfil;&lt;br&gt;
seguir perfil;&lt;br&gt;
visualizar lista de seguidores e perfis seguidos;&lt;br&gt;
criação de publicação;&lt;br&gt;
associação de comentários;&lt;br&gt;
filtro e ordenação de publicações;&lt;/p&gt;

&lt;p&gt;A construção destes serviços envolverá passar pelo jeito tradicional (e que PRECISA mudar) de escrever programas Advpl para uma forma que permita isolar o negócio e eventualmente permitir evoluções de tecnologia que não envolva mexer na regra de de negócio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como acompanhar
&lt;/h2&gt;

&lt;p&gt;O projeto no Github &lt;a href="https://github.com/josimar-jr/microblog-protheus"&gt;https://github.com/josimar-jr/microblog-protheus&lt;/a&gt; terá os códigos baseados em branches que serão mantidas conforme o projeto for evoluindo para permitir a comparação com versões anteriores dos programas.&lt;br&gt;
Este projeto terá também alguns dos recursos base para conseguir replicar o ambiente utilizado e cada pessoa conseguir testar em ambiente de desenvolvimento.&lt;br&gt;
Parte do desenvolvimento será apoiado com testes usando o Postman e por isso não será usado nenhum recurso de teste automatizado próprio para Protheus ou Advpl.&lt;/p&gt;

&lt;p&gt;Até a próxima página dessa jornada.&lt;/p&gt;

</description>
      <category>advpl</category>
      <category>rest</category>
      <category>protheus</category>
      <category>api</category>
    </item>
  </channel>
</rss>
