Entendo os métodos PUT, POST e UPDATE

Apenas corrigindo o título do blog, os métodos são:

GET, PUT e POST

Como vimos na primeira postagem sobre WS REST, em um serviço podemos ter 4 métodos dos quais são POST, UPDATE, DELETE e GET, cada um desses métodos retorna um código HTTP sendo de sucesso ou erro.

Abaixo iremos entender o funcionamento dos métodos PUT, POST e UPDATE e faremos um programinha para ver como isso funciona no ADVPL.

Na explicação do método, irei focar na explicação apenas do que se diz respeito ao REST, o restante é o nosso conhecido ADVPL. Porém caso tenha algum tipo de dúvida, PERGUNTE

 

GET:

O método GET é responsável por retornar ao cliente chamador alguma coisa qualquer, como por exemplo uma lista de clientes cadastrados.

Vamos ver abaixo um exemplo de método get:

WSMETHOD GET WSSERVICE CLIENTES

Local aArea        := GetArea()

Local cNextAlias   := GetNextAlias()

Local oCliente    := CLIENTES():New() // –> Objeto da classe cliente

Local oResponse    := FULL_CLIENTES():New() // –> Objeto que será serializado

Local cJSON       := “”

Local lRet        := .T.

 

BeginSQL Alias cNextAlias

SELECT A1_COD, A1_LOJA, A1_NOME, A1_END, A1_CGC, A1_CEP, A1_DDD, A1_TEL

FROM %table:SA1% SA1

WHERE SA1.%notdel%

EndSQL

(cNextAlias)->( DbGoTop() )

If (cNextAlias)->( !Eof() )

While (cNextAlias)->( !Eof() )

oCliente:SetCodigo( AllTrim((cNextAlias)->A1_COD ))

oCliente:SetLoja(       AllTrim((cNextAlias)->A1_LOJA))

oCliente:SetNome(       AllTrim((cNextAlias)->A1_NOME))

oCliente:SetCGC( AllTrim((cNextAlias)->A1_CGC ))

oCliente:SetCEP( AllTrim((cNextAlias)->A1_CEP ))

oCliente:SetEnd( AllTrim((cNextAlias)->A1_END ))

oCliente:SetDDD( AllTrim((cNextAlias)->A1_DDD ))

oCliente:SetTel(  AllTrim((cNextAlias)->A1_TEL ))

oResponse:Add(oCliente)

(cNextAlias)->( DbSkip() )

EndDo

cJSON := FWJsonSerialize(oResponse, .T., .T.,,.F.)

::SetResponse(cJSON)

Else

SetRestFault(400, “SA1 Empty”)

lRet := .F.

EndIf

RestArea(aArea)

Return(lRet)

Explicação do trecho de código acima:

Como vimos na primeira postagem, para serialização de um objeto JSON, precisamos passar um objeto para a função FWJSONSerialize, para isso nas linhas 5 e 6 temos a declaração de duas variáveis que são objetos das classes CLIENTES e FULL_CLIENTES.

  • CLIENTES é onde armazenamos os atributos do cliente.
  • FULL_CLIENTES é onde armazenamos uma lista dos objetos da classe CLIENTES

Logo a seguir fazemos uma query na tabela de clientes (SA1).

Na linha 19 temos a condição (cNextAlias)->( !Eof() ) , nesse momento eu verifico se a minha query retornou algum resultado.

Retorno da condicional positivo:

Caso tenha retornado então iremos alimentar os objetos como podemos ver o trecho de código entre as linhas 21 e 35.

Entre as linhas 23 e 30 alimentamos o objeto oCliente com os dados do cliente.

Na linha 32 adicionamos o objeto cliente já alimentado, na lista de clientes oResponse pois será essa lista que iremos serializar.

Após sair do loop onde alimentamos os objetos, utilizamos o seguinte comando para transformar a nossa lista de clientes (oResponse) em uma string JSON serializada e na sequência utilizamos o comando SetResponse para enviar a string ao cliente.

cJSON := FWJsonSerialize(oResponse, .T., .T.,,.F.)

::SetResponse(cJSON)

Retorno da condicional negativo:

Caso minha query não retorne nenhum registro então iremos utilizar a função SetRestFault para retornar um código HTTP de erro e uma mensagem.

SetRestFault(400, “SA1 Empty”)

Exemplo de retorno com o resultado negativo da condicional (sem dados no SA1):

1

Exemplo de retorno com o resultado positivo da condicional (com dados no SA1):

2

POST:

O método POST é responsável por incluir ou processar algum tipo de informação enviada pelo client.

Vamos ver abaixo um exemplo de método post:

Iremos receber um JSON com dados de um cliente e realizar a inclusão do mesmo caso não exista na base de dados.

Estrutura do JSON que vamos receber:

1

WSMETHOD POST WSRECEIVE RECEIVE WSSERVICE CLIENTES

Local cJSON        := Self:GetContent() // Pega a string do JSON

Local oParseJSON := Nil

Local aDadosCli   := {} //–> Array para ExecAuto do MATA030

Local cFileLog   := “”

Local cJsonRet   := “”

Local cArqLog     := “”

Local cErro       := “”

Local cCodSA1     := “”

Local lRet        := .T.

Private lMsErroAuto := .F.

Private lMsHelpAuto := .F.

// –> Cria o diretório para salvar os arquivos de log

If !ExistDir(“\log_cli”)

MakeDir(“\log_cli”)

EndIf

// –> Deserializa a string JSON

FWJsonDeserialize(cJson, @oParseJSON)

SA1->( DbSetOrder(3) )

If !(SA1->( DbSeek( xFilial(“SA1”) + oParseJSON:CLIENTE:CGC ) ))

cCodSA1 := GetNewCod()

Aadd(aDadosCli, {“A1_FILIAL”  , xFilial(“SA1”)  , Nil} )

Aadd(aDadosCli, {“A1_COD”     , cCodSA1   , Nil} )

Aadd(aDadosCli, {“A1_LOJA”    , “01”      , Nil} )

Aadd(aDadosCli, {“A1_CGC”     , oParseJSON:CLIENTE:CGC  , Nil} )

Aadd(aDadosCli, {“A1_NOME”    , oParseJSON:CLIENTE:NOME , Nil} )

Aadd(aDadosCli, {“A1_NREDUZ”  , oParseJSON:CLIENTE:NOME , Nil} )

Aadd(aDadosCli, {“A1_END”     , oParseJSON:CLIENTE:ENDERECO ,Nil}

Aadd(aDadosCli, {“A1_PESSOA”  , Iif(Len(oParseJSON:CLIENTE:CGC)== 11, “F”, “J”)          , Nil} )

Aadd(aDadosCli, {“A1_CEP”  , oParseJSON:CLIENTE:CEP    , Nil} )

Aadd(aDadosCli, {“A1_TIPO” , “F”                       , Nil} )

Aadd(aDadosCli, {“A1_EST”  , oParseJSON:CLIENTE:ESTADO , Nil} )

Aadd(aDadosCli, {“A1_MUN”  , oParseJSON:CLIENTE:MUNICIPIO,Nil} )

Aadd(aDadosCli, {“A1_TEL”  , oParseJSON:CLIENTE:TELEFONE, Nil} )

MsExecAuto({|x,y| MATA030(x,y)}, aDadosCli, 3)

If lMsErroAuto

cArqLog := oParseJSON:CLIENTE:CGC + ” – ” +SubStr(Time(),1,5 ) + “.log”

RollBackSX8()

cErro := MostraErro(“\log_cli”, cArqLog)

cErro := TrataErro(cErro) // –> Trata o erro para devolver para o client.

SetRestFault(400, cErro)

lRet := .F.

Else

ConfirmSX8()

cJSONRet := ‘{“cod_cli”:”‘ + SA1->A1_COD + ‘”‘;

+ ‘,”loja”:”‘  + SA1->A1_LOJA      + ‘”‘;

+ ‘,”msg”:”‘  + “Sucesso”          + ‘”‘;

+’}’

::SetResponse( cJSONRet )

EndIf

Else

SetRestFault(400, “Cliente já cadastrado: ” + SA1->A1_COD + ” – ” + SA1->A1_LOJA)

lRet := .F.

EndIf

Return(lRet)

Explicação do trecho de código acima:

Linha 3 -> Pega o JSON recebido e armazena na variável cJson

Linha 19 -> Deserializa Json recebido utilizando a função FWJsonDeserialize e disponibiliza os dados do mesmo no objeto oParseJSON.

Na linha 22 temos uma condicional que verifica se o CPF/CNPJ recebido já consta em nossa base de dados.

Retorno Negativo da condicional:

Caso o CGC informado não exista na nossa base de dados, então vamos realizar a inclusão do cliente usando ExecAuto.

Montamos o array e chamamos a função MsExecAuto.

Retorno para o Client:

  • Se no MsExecAuto der algum tipo de inconsistência então retornamos a mensagem de inconsistência para o cliente utilizando a função SetRestFault como podemos ver na linha 51.
  • Caso contrário eu devolvo um JSON com o código e loja do cliente que acabou de ser incluído, como podemos ver na linha 59.
    • Repare que na linha 59 eu estou utilizando o comando SetResponse utilizando uma string que montei “na unha”, como podemos ver no seguinte trecho:

 

cJSONRet := ‘{“cod_cli”:”‘ + SA1->A1_COD + ‘”‘;

+ ‘,”loja”:”‘  + SA1->A1_LOJA      + ‘”‘;

+ ‘,”msg”:”‘  + “Sucesso”          + ‘”‘;

+’}’

Sim … Podemos montar o nosso JSON “na unha”, apesar de ser muito mais trabalhoso.

Exemplo de retorno com erro do execauto:

1

Exemplo de retorno com um cliente já existente na base de dados:

2

Exemplo de retorno com sucesso na inclusão de um cliente:

3

PUT:

O método PUT é responsável por alterar algum tipo de informação enviada pelo client.

Vamos ver abaixo um exemplo de método put:

Iremos receber um JSON com dados de um cliente e realizar a alteração do mesmo caso exista na base de dados.

Neste exemplo teremos parâmetros recebidos via URL que no caso será o CGC (cpf ou cnpj) do cliente que queremos realizar a alteração e o conteúdo via JSON que será recebido via POST-Request (no corpo da requisição HTTP).

Estrutura da JSON que iremos receber:

1

WSMETHOD PUT WSRECEIVE RECEIVE WSSERVICE CLIENTES

Local cJSON := Self:GetContent() // –> Pega a string do JSON

Local cCGC  := Self:CGC // –> Pega o parâmetro recebido pela URÇ

Local lRet  := .T.

Local oParseJSON := Nil

Local aDadosCli   := {} //–> Array para ExecAuto do MATA030

Local cJsonRet   := “”

Local cArqLog     := “”

Local cErro       := “”

Private lMsErroAuto := .F.

If !ExistDir(“\log_cli”)

MakeDir(“\log_cli”)

EndIf

::SetContentType(“application/json”)

// –> Deserializa a string JSON

FWJsonDeserialize(cJson, @oParseJSON)

SA1->( DbSetOrder(3) )

If (SA1->( DbSeek( xFilial(“SA1”) + cCGC ) ))

   Aadd( aDadosCli, {“A1_NOME”, oParseJSON:CLIENTE:NOME     , Nil } )

Aadd( aDadosCli, {“A1_END” , oParseJSON:CLIENTE:ENDERECO , Nil } )

MsExecAuto({|x,y| MATA030(x,y)}, aDadosCli, 4)

If lMsErroAuto

cArqLog := oParseJSON:CLIENTE:CGC + ” – ” + SubStr( Time(),1,5 ) + “.log”

cErro := MostraErro(“\log_cli”, cArqLog)

cErro := TrataErro(cErro) // –> Trata o erro para devolver para o client.

SetRestFault(400, cErro)

lRet := .F.

Else

cJSONRet := ‘{“cod_cli”:”‘ + SA1->A1_COD + ‘”‘;

+ ‘,”loja”:”‘  + SA1->A1_LOJA      + ‘”‘;

+ ‘,”msg”:”‘   + “Alterado”   + ‘”‘;

+’}’

::SetResponse( cJSONRet )

EndIf

Else

SetRestFault(400, “Cliente não encontrado.”)

lRet := .F.

EndIf

Return(lRet)

O único ponto de atenção que deveremos ter nesse método é a linha 4, pois é ali que recebemos o CGC do cliente informado através da URL no qual iremos modificar.

Todo o restante dos comandos, já está explicado nos métodos POST e GET.

Exemplo de requisição efetuada com sucesso:

1

Exemplo de requisição efetuada com erro:

2

Link do GitHub:

https://github.com/VctrAndrade/RestAdvplPost02

Bom pessoal, espero que gostem e nos envie sugestões também 🙂

Abraços!

Anúncios

8 comentários em “Entendo os métodos PUT, POST e UPDATE

  1. Boa tarde Vitor,

    Primeiramente parabéns pelo conteúdo, é algo que irá ajudar a muitos analistas Protheus como eu.
    Uma dúvida, o método GET do seu exemplo está retornando várias vezes o mesmo registro, por acaso você já teria esta correção para compartilhar ?

    Abraços

    Curtir

      1. Boa tarde Vitor,

        Encontrei a solução para o erro, é só recriar o objeto oCliente antes do loop, ficando assim:

        oResponse:Add(oCliente)
        oCliente := CLIENTES():New()

        Fiz uma melhoria para filtrar com lógica SQL,

        WSMETHOD GET WSRECEIVE FILTER WSSERVICE CLIENTES
        Local cFilter := “%”+ Self:FILTER +”%”
        Local aArea := GetArea()
        Local cNextAlias := GetNextAlias()
        Local oCliente := CLIENTES():New() // –> Objeto da classe cliente
        Local oResponse := FULL_CLIENTES():New() // –> Objeto que será serializado
        Local cJSON := “”
        Local lRet := .T.

        ::SetContentType(“application/json”)

        if Empty(cFilter)
        BeginSQL Alias cNextAlias
        SELECT A1_COD, A1_LOJA, A1_NOME, A1_END, A1_CGC, A1_CEP, A1_DDD, A1_TEL
        FROM %table:SA1% SA1
        WHERE SA1.%notdel%
        EndSQL
        Else
        BeginSQL Alias cNextAlias
        SELECT A1_COD, A1_LOJA, A1_NOME, A1_END, A1_CGC, A1_CEP, A1_DDD, A1_TEL
        FROM %table:SA1% SA1
        WHERE %exp:cFilter% AND SA1.%notdel%
        EndSQL
        EndIf

        Tenho uma sugestão sim, assistindo o webinar Fluig Serviços em: https://www.youtube.com/watch?v=ksEnyXnIoRo&t=30s , que é referente a integração utilizando o REST, o que me interessou foi o REST das rotinas padrões, MATA010, MATA030 etc..

        Pelo que entendi é um recurso que já está disponível, mas ainda não conseguir fazer rodar..

        Abraços

        Curtir

      2. Muito bom Tiago!

        Era exatamente isso que deveria ser feito para correção do erro que eu deixei no POST.

        Só que se formos seguir as boas práticas da Orientação a Objetos (O.O), não devemos instanciar o objeto a cada loop e sim criar um método para “limpar” o objeto temporário antes de setar os valores novamente.

        De qualquer maneira muito obrigado e inclusive vou subir um branch no github com a sua versão.

        Quanto a sua sugestão, existe sim essa possibilidade, porém quando a rotina é desenvolvida em MVC. Estou montando o próximo POST justamente demonstrando a utilização do WS Rest default do MVC.

        Abraços.

        Curtir

  2. Victor , bom dia , Excelente Post , esta me ajudando bastante , mas me tira uma duvida , estou recebendo o seguinte erro , ao chamar o método GET “invalid class CLIENTES” , O que posso esta fazendo de errado ?

    Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s