Um microblog usando Protheus - Rest Server, parte 3, serviço padrão rest de modelos mvc
Tags: advpl, rest, mvc, api
Published: 2020-12-03 00:53:49

#Introdução
Nesta parte será apresentado o serviço de rest padrão que é oferecido quando utilizado MVC.
Para um bom entendimento de como funciona é importante que a pessoa esteja familiarizada com a construção de modelos de dados para MVC.
O conteúdo disponível oficialmente sobre MVC está no [link](https://tdn.totvs.com/display/public/PROT/AdvPl+utilizando+MVC).

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.
[Segunda parte](https://dev.to/josimar_jr_/um-microblog-usando-protheus-rest-server-parte-2-1bch)

# A construção do modelo de dados
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.

O `ModelDdef` ficou assim:
```c
static function ModelDef()
    local oModel   as object
    local oStrZT0  as object

    oStrZT0 := FWFormStruct(1, "ZT0")
    oModel := MpFormModel():New("ZMBMODEL")

    oModel:AddFields("ZT0_FIELDS", , oStrZT0)
    oModel:SetDescription("Cadastro de perfis")
    oModel:GetModel("ZT0_FIELDS"):SetDescription("Perfis")
return oModel
```
Os detalhes importantes neste modelo são:
- as descrições para o modelo completo e para o cabeçalho/enchoice;
- o id como `ZMBMODEL`, 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 `U_ZMBMODEL`.

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 `PUBLISH USER MODEL` ou `PUBLISH MODEL`, respectivamente para funções de usuário e funções do padrão.

A documentação sobre os recursos oferecidos quando estes comandos são adicionados a fontes compilados estão descritos nessas documentações.
[Publicando um modelo como rest](https://tdn.totvs.com/display/framework/4.+Publicando+o+REST+do+Model)
[FwRestModel](https://tdn.totvs.com/display/public/PROT/FWRestModel)

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.
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.

# Fazendo a publicação de um modelo
Para o modelo MVC do cadastro de Perfis foi realizada duas publicações de serviços: uma com o id `perfis` e outra com o id `ZMBA010`.
Os comandos que fizeram estas publicações foram:
```c
// http://localhost:18085/rest/fwmodel/Perfis/
PUBLISH USER MODEL REST NAME Perfis SOURCE ZMBA010

// http://localhost:18085/rest/fwmodel/ZMBA010/
PUBLISH USER MODEL REST NAME ZMBA010 SOURCE ZMBA010
```
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 `.../fwmodel/ZMBA010/{chave}` a recuperação de dados e informações sobre o cadastro MVC.
Essa URI é a padrão para qualquer programa, portanto qualquer programa que teve seu modelo publicado ficará acessível a partir da URI `/fwmodel/{programa}/{chave}`.

# Explorando o modelo exposto
Três endpoints são disponibilizados para permitir a leitura e análise de informações sobre o modelo publicado.

- `/schema` - 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.
- `/xmldata` - retorna a estrutura de um item para ser utilizado posteriormente nas operações de `POST` e `PUT`.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<ZMBMODEL Operation="1" version="1.01">
    <ZT0_FIELDS modeltype="FIELDS">
        <ZT0_FILIAL order="1">
            <value></value>
        </ZT0_FILIAL>
        <ZT0_USRID order="2">
            <value></value>
        </ZT0_USRID>
        <ZT0_EMAIL order="3">
            <value></value>
        </ZT0_EMAIL>
        <ZT0_NOME order="4">
            <value></value>
        </ZT0_NOME>
    </ZT0_FIELDS>
</ZMBMODEL>
```
- `/xmldatadetail` - retorna a estrutura de um item (como o anterior) e com detalhes adicionais como tamanho, tipo do dado, título e obrigatoriedade.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<ZMBMODEL Operation="1" version="1.01">
    <ZT0_FIELDS modeltype="FIELDS">
        <ZT0_FILIAL order="1" len="2,0" datatype="C" info="Filial" >
            <value></value>
        </ZT0_FILIAL>
        <ZT0_USRID order="2" len="6,0" datatype="C" info="cod usuário" obrigat="1" >
            <value></value>
        </ZT0_USRID>
        <ZT0_EMAIL order="3" len="100,0" datatype="C" info="email" obrigat="1" >
            <value></value>
        </ZT0_EMAIL>
        <ZT0_NOME order="4" len="100,0" datatype="C" info="nome" obrigat="1" >
            <value></value>
        </ZT0_NOME>
    </ZT0_FIELDS>
</ZMBMODEL>
```

Estes endpoints somente retornam no formato `application/xml`.

# Recuperando dados usando o modelo
Os métodos e operações permitidos estão na tabela a seguir.

método|path|objetivo|usa informação do...
---|---|---|---
POST|`/fwmodel/Perfis/`|incluir um registro|body
GET|`/fwmodel/Perfis/`|incluir um registro|parâmetros de query
GET|`/fwmodel/Perfis/{pk}`|incluir um registro|parâmetros de query
PUT|`/fwmodel/Perfis/{pk}`|incluir um registro|body
DELETE|`/fwmodel/Perfis/{pk}`|incluir um registro|nenhum

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.

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

Os exemplos de como usar os endpoints estão na coleção do postman no [repositório](https://github.com/josimar-jr/microblog-protheus/tree/main/resources/postman).

# Detalhes da api
A principal diferença para o serviço construído antes são as novas possibilidades que a publicação do padrão permite.

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.
- paginação: combinando as propriedades `count` e `startindex` é possível fazer a paginação, um exemplo é a expressão `/fwmodel/zmba010?count=20&startindex=2` que traria os registros de `21 a 40` conforme a ordem usada no modelo (normalmente a ordem de índice 1).
- filtragem: com a propriedade `filter` é possível determinar uma expressão que irá restringir o resultado, como `filter=ZT0_ADMIN = 1`.
- restrição de campos: com a propriedade `fields` é 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 `fields=ZT0_USRID,ZT0_NOME` faria retornar somente os campos `ZT0_USRID` e `ZT0_NOME`.

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.

# O modelo avançado
[Nessa documentação já citada](https://tdn.totvs.com/display/public/PROT/FWRestModel) existe um recurso não utilizado na publicação do modelo para Perfis.
A opção `RESOURCE OBJECT <objeto>` 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). 
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.
Na documentação tem o fonte `FWRestModelObject.prx` com uma implementação bem similar a do padrão e um exemplo com a implementação simulada para um serviço de filiais.

# Conclusão
Este é um tópico em que é importante utilizar a coleção do postman e os endpoints para ver as coisas acontecerem no sistema.
Muito é oferecido somente com a publicação do modelo e cadastros simples são bem atendidas somente com isso.
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.
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 `Reclock` ou `Insert`.