O código-fonte de uma classe REST segue o modelo de classes AdvPL e SOAP, porém os métodos são limitados aos suportados pela implementação do protocolo no AdvPL (POST, PUT, GET e DELETE).

Atenção

Caso uma nova classe REST seja compila após a inicialização do HTTP_START será necessário reiniciar o Application Server para que a mesma seja publicada 

Passos para criação da classe:

  1. Incluir os includes TOTVS.CH e RESTFUL.CH

    #INCLUDE "TOTVS.CH"
    #INCLUDE "RESTFUL.CH"

     Declarar a classe com o comando WSRESTFUL

    WSRESTFUL sample DESCRIPTION "Exemplo de serviço REST"
    O nome declarado após o comando WSRESTFUL será utilizado no endereço (URI) para execução dos métodos (respeitando a configuração de URL do appserver.ini), por exemplo http://localhost:8080/rest/sample

         

  2. Declarar com o comando WSDATA as propriedades que serão utilizadas para receber os parâmetros de QueryString (opcional)

    WSDATA count AS INTEGER
    WSDATA startIndex AS INTEGER 

        

  3. MODO LEGADO: Declarar com o comando WSMETHOD <method> DESCRIPTION os métodos HTTP que serão utilizados (POST, PUT, GET e DELETE), não sendo obrigatório declarar todos, somente os que serão utilizados

    WSMETHOD GET DESCRIPTION "Exemplo de retorno de entidade(s)" WSSYNTAX "/sample || /sample/{id}"
    WSMETHOD POST DESCRIPTION "Exemplo de inclusao de entidade" WSSYNTAX "/sample/{id}"
    WSMETHOD PUT DESCRIPTION "Exemplo de alteração de entidade" WSSYNTAX "/sample/{id}"
    WSMETHOD DELETE DESCRIPTION "Exemplo de exclusão de entidade" WSSYNTAX "/sample/{id}"

        

  4. MODO RECOMENDADO: Declarar com o comando WSMETHOD <method> <id> DESCRIPTION os métodos HTTP que serão utilizados (POST, PUT, GET e DELETE), não sendo obrigatório declarar todos, somente os que serão utilizados. A diferença em relação ao modo legado é que dessa forma é possível ter mais que um verbo na mesma classe, por exemplo, 2 GETs 2 PUTs, desde que seja nomeado corretamente com o <id> 

    WSMETHOD GET ALL DESCRIPTION "Exemplo de retorno de todas as entidade(s)" PATH "/sample
    WSMETHOD POST ID DESCRIPTION "Exemplo de inclusao de entidade" PATH "/sample/{id}"
    WSMETHOD PUT ID DESCRIPTION "Exemplo de alteração de entidade" PATH "/sample/{id}"
    WSMETHOD DELETE ID DESCRIPTION "Exemplo de exclusão de entidade" PATH "/sample/{id}"
    WSMETHOD GET ID2 DESCRIPTION "Exemplo de retorno de entidade(s) sem validar empresas" PATH "/sample/{id}" NOTENANT

    NOTENANT adicionado no último método tem como função não validar empresa/filial do usuário, com ele apenas será realizada a autenticação do mesmoCom isso, não terá necessidade de adicionar a chave TenantId no Header da requisição.


  5. Finalizar a declaração da classe com o comando END WSRESTFUL 

     END WSRESTFUL 

       

  6. Implementar os métodos que foram declarados com o comando WSMETHOD <method> WSSERVICE <rest>

    WSMETHOD GET WSRECEIVE startIndex, count WSSERVICE sample
    Local i
    
    // define o tipo de retorno do método
    ::SetContentType("application/json")
     
    // verifica se recebeu parametro pela URL
    // exemplo: http://localhost:8080/sample/1
    If Len(::aURLParms) > 0
       // insira aqui o código para pesquisa do parametro recebido
       // exemplo de retorno de um objeto JSON 
       ::SetResponse('{"id":' + ::aURLParms[1] + ', "name":"sample"}')
    Else
       // as propriedades da classe receberão os valores enviados por querystring
       // exemplo: http://localhost:8080/sample?startIndex=1&count=10
     
       DEFAULT ::startIndex := 1, ::count := 5
     
       // exemplo de retorno de uma lista de objetos JSON
       ::SetResponse('[')
     
       For i := ::startIndex To ::count + 1
           If i > ::startIndex
              ::SetResponse(',')
           EndIf
           ::SetResponse('{"id":' + Str(i) + ', "name":"sample"}')
       Next
       ::SetResponse(']')
    EndIf
    Return .T.
    
    
    WSMETHOD POST WSSERVICE sample
    Local lPost := .T.
    
    // Exemplo de retorno de erro
    If Len(::aURLParms) == 0
       SetRestFault(400, "id parameter is mandatory")
       lPost := .F.
    Else
       // insira aqui o código para operação inserção
       // exemplo de retorno de um objeto JSON 
       ::SetResponse('{"id":' + ::aURLParms[1] + ', "name":"sample"}')
    EndIf
    Return lPost
    
    Observações
    Os parâmetros de QueryString devem ser declarados novamente no métodos que irão utilizados com o comando WSRECEIVE

     A propriedade aURLParms contém os parâmetros de endereço (PathParam) recebido

    Exemplos:

     - http://localhost:8080/rest/sample/1
       Valor de ::aURLParms é { "1" }

     - http://localhost:8080/sample/1/test
       Valor de ::aURLParms é { "1", "test" }

     Os métodos devem retornar verdadeiro (.T.) em caso de sucesso no processamento ou falso (.F.) em caso de falha utilizando a função SetRestFault para definir o código HTTP de erro para retorno




  • Sem rótulos

4 Comentários

  1. Seguem algumas informações adicionais para quem esta criando os serviços RESTful, como foram observações mediante testes, podem sofrer alterações ou não refletir 100% do funcionamento da API:

    Ao definir o WSMETHOD dentro do WSRESTFUL é bom utilizar a seguinte construção:

    WSMETHOD GET id_do_servico ;
    DESCRIPTION "descricao para o servico" ;
    WSSYNTAX "assets/{pathparam1}/{pathparam2}" ;
    PATH "assets/{pathparam1}/{pathparam2}"
    • É importante informa o id_do_serviço para caso existam diversas chamadas GET no mesmo objeto (isto também se aplica aos outros métodos).

    • É importante colocar a mesma informação do WSSYNTAX no PATH, pois é o PATH que faz a relação dos parâmetros posicionais com os atributos do seu objeto (e não o WSSYNTAX como dá a entender).

    • É importante criar os atributos com o WSDATA dentro da definição do WSRESTFUL para cada parâmetro posicional informado no PATH

    • É útil informar o WSSYNTAX pois ele compõem a documentação do serviço mostrando os parâmetros posicionais.

    Ao definir o WSDATA dentro do WSRESTFUL é bom utilizar a seguinte construção:

    WSDATA pathparam1 AS type
    • É importante definir o type, podendo ser um dos que estão documentados em WSDATA. Esses tipos são utilizados para fazer as conversões automaticamente, caso não seja informado todos os parâmetros serão texto, e você terá de fazer a conversão manualmente.

    Ao criar o WSMETHOD fora do WSRESTFUL é bom utilizar a seguinte construção:

    WSMETHOD GET id_do_servico PATHPARAM pathparam1,pathparam2 WSRECEIVE queryparam1,queryparam2 WSSERVICE classe_do_restful
    • É obrigatorio informar a classe_do_restful na instrução WSSERVICE

    • É importante informar o id_do_servico, pois podemos ter mais de um método com o verbo GET (isso também se aplica para os outros verbos)

    • É útil informar PATHPARAM pois ele irá facilitar a página de documentação do serviço apresentando quais são os parâmetros que serão lidos pelo caminho da url

    • É útil informar WSRECEIVE pois ele irá facilitar a página de documentação do serviço apresentando quais são os parâmetros que serão lidos do querystring

    OBS: É importante observar que apontar as instruções PATHPARAM e WSRECEIVE alteram a documentação e criam variáveis locais com os nomes dos atributos. Porem esses atributos são acessados pela classe sendo necessário utilizar a notação Self:pathparam1 ou ::pathparam1

    1. Usuário desconhecido (denis.rodrigues)

      Daniel Fonseca de Lira tudo bem?

      Estava criando um serviço RESTFULL com as instruções que tu mencionou, mas de cara só informando o id do serviço o TDS já não compila e mostra "C2003 SYNTAX ERROR ".

      Essas instruções servem para a Build 12.1.17?

      Obrigado

      1. Olá Denis, faz um tempo que postei e que não mexo com o REST do Protheus não sei afirmar se ainda funciona da mesma forma, mas questão de SYNTAX ERROR pode ter relação com o RESTFUL.CH, praticamente todo o processo do REST é feito em pré-processamento, então tenha certeza que os includes estão atualizados.

      2. ¿Pudiste solucionar el error?