Serviços RESTful no Adianti Framework 7 No artigo anterior (https://www.adianti.com.br/forum/pt/view_4691), vimos como criar um serviço REST. Agora vamos proceder com a criação de um serviço RESTful. Habilitando o servidor O primeiro passo é habilitar um servidor REST no Adianti Framework. Para tal, se sua aplicação é baseada no Template, este arquivo já é fornecido, e basta renomear o arquivo rest.php.di...
PD
Serviços RESTful no Adianti Framework 7  


No artigo anterior (https://www.adianti.com.br/forum/pt/view_4691), vimos como criar um serviço REST. Agora vamos proceder com a criação de um serviço RESTful.

Habilitando o servidor


O primeiro passo é habilitar um servidor REST no Adianti Framework. Para tal, se sua aplicação é baseada no Template, este arquivo já é fornecido, e basta renomear o arquivo rest.php.dist para rest.php e o servidor estará no ar.

Como este arquivo disponibiliza as classes do Framework para utilização externa, é imprescindível implementar um mecanismo de controle, ou seja, filtrar somente as requisições válidas. Para tal, foi colocado ali no arquivo um lembrete (// aqui implementar mecanismo de controle).

Classe de modelo


Antes de disponibilizar um serviço, é necessário termos a classe de entidade previamente declarada na pasta app/model ou em algum subdiretório. Se você já usa o Framework, provavelmente já tem várias classes de modelo.

app/model/Contact.php
  1. <?php
  2. class Contact extends TRecord
  3. {
  4.     const TABLENAME 'contact';
  5.     const PRIMARYKEY'id';
  6.     const IDPOLICY =  'max'// {max, serial}
  7.     public function __construct($ID NULL$callObjectLoad TRUE)
  8.     {
  9.         parent::__construct($ID$callObjectLoad);
  10.         parent::addAttribute('name');
  11.         parent::addAttribute('email');
  12.         parent::addAttribute('number');
  13.         parent::addAttribute('address');
  14.         parent::addAttribute('notes');
  15.     }
  16. }
  17. ?>


Criando a classe de serviço


Provavelmente você já tem uma série de classes de modelo representando suas tabelas na pasta app/model. Agora, queremos criar um Web Service para disponibilizar uma API para manipular uma classe de modelo. Para tal, precisamos criar uma classe de serviço. Uma classe de serviço cria uma camada que interage com uma funcionalidade interna da aplicação e a expõe para o mundo externo. Neste caso, vamos criar a classe app/service/ContactService.php. É necessário configurar ainda a constante DATABASE com o nome do conector de base de dados (existente em app/config/contacts.ini), e a constante ACTIVE_RECORD para conter o nome da classe de modelo (existente em app/model/Contact.php) que será disponibilizada. Ao usarmos a classe AdiantiRecordService como base (herança), a classe de serviço já herdará uma série de métodos REST como: load(), store(), delete(), loadAll(), e deleteAll().

app/service/ContactRestService.php
  1. <?php
  2. class ContactRestService extends AdiantiRecordService
  3. {
  4.     const DATABASE      'contacts';
  5.     const ACTIVE_RECORD 'Contact';
  6. }
  7. ?>


Configurando as rotas


Para cada classe de serviço a ser disponibilizada, devem ser criadas três rotas. A primeira é usada para operações com objetos individuais como um GET ou PUT para /contacts/1, já a segunda é usada para ações personalizadas sobre objetos individuais como /contacts/1/action, e a terceira é usada para operações em lote como um GET ou POST para /contacts. Para cada nova classe de serviço criada, você deve replicar essas três linhas, substituindo "contacts" do primeiro segmento pelo nome do objeto manipulado, e "ContactRestService" do segundo segmento pelo nome da classe de serviço a ser disponibilizada.

.htaccess
#RESTFUL routes
RewriteRule ^contacts/([A-Za-z0-9]*)$ rest.php?class=ContactRestService&method=handle&id=$1&%{QUERY_STRING} [NC]
RewriteRule ^contacts/([A-Za-z-_0-9]*)/([A-Za-z-_0-9]*)$ rest.php?class=ContactRestService&method=$2&id=$1&%{QUERY_STRING} [NC]
RewriteRule ^contacts$ rest.php?class=ContactRestService&method=handle&%{QUERY_STRING} [NC]

Preparando os testes


Para preparar os testes, precisaremos de uma função para realizar requisições para uma URL do sistema. Para tal, vamos criar uma função chamada request(), que receberá a localização do serviço no primeiro parâmetro, o método no segundo parâmetro (GET, POST, PUT, DELETE), e um vetor com os dados da postagem no terceiro parâmetro. Esta função de testes está no link a seguir.

request.php
https://pastebin.com/jmXjD1pw


Carregar registro em PHP


Para carregar um registro em PHP, realizamos um request do tipo GET para a URL contendo o endpoint com o registro a ser consultado /contacts/<id>.

  1. <?php
  2. require_once 'request.php';
  3. try
  4. {
  5.     $location 'http://localhost/sistema/contacts/1';
  6.     print_rrequest($location'GET') );
  7. }
  8. catch (Exception $e)
  9. {
  10.     echo 'Error: ' $e->getMessage();
  11. }
  12. ?>


O retorno será um objeto com os dados.

Retorno
stdClass Object ( [id] => 1 [name] => Mary [email] => mary@mary.com [number] => +55 (51) 1234-5678 [address] => Mary Street, 123 Philadephia [notes] => Good customer )


Carregar registro em Javascript


Para carregar um registro em Javascript, realizamos um request do tipo GET para a URL contendo o endpoint com o registro a ser consultado /contacts/<id>.

$.ajax({ type: 'GET', url: 'http://localhost/sistema/contacts/1', success: function (response) { console.log(response.data); } });


O retorno será um objeto com os dados.

Retorno
{ "id": "1", "name": "Mary", "email": "mary@mary.com", "number": "+55 (51) 1234-5678", "address": "Mary Street, 123 Philadephia", "notes": "Good customer" }


Carregar registro em Shell


Para carregar um registro em Shell, realizamos um request do tipo GET para a URL contendo o endpoint com o registro a ser consultado /contacts/<id>.

curl -i -X GET http://localhost/sistema/contacts/1


O retorno será um objeto com os dados.

Retorno
HTTP/1.1 200 OK {"status":"success","data":{"id":"1","name":"Mary","email":"mary@mary.com","number":"+55 (51) 1234-5678","address":"Mary Street, 123 Philadephia","notes":"Good customer"}}


Criar registro em PHP


Para criar um registro em PHP, realizamos um request do tipo POST para a URL contendo o endpoint /contacts, identificando no terceiro parâmetro o vetor com os dados do objeto.

  1. <?php
  2. require_once 'request.php';
  3. try
  4. {
  5.     $body = [];
  6.     $body['name'] = 'Dino';
  7.     $location 'http://localhost/sistema/contacts';
  8.     print_rrequest($location'POST'$body) );
  9. }
  10. catch (Exception $e)
  11. {
  12.     echo 'Error: ' $e->getMessage();
  13. }
  14. ?>


O retorno será um objeto com os dados.

Retorno
stdClass Object ( [name] => Dino [id] => 3 )


Criar registro em Javascript


Para criar um registro em Javascript, realizamos um request do tipo POST para a URL contendo o endpoint /contacts, identificando os dados do objeto na posição data.

$.ajax({ type: 'POST', url: 'http://localhost/sistema/contacts', data: { 'name': 'Dino', 'email': 'dino@mail.com' }, dataType: 'json', success: function (response) { console.log(response.data); } });


O retorno será um objeto com os dados.

Retorno
{ "name": "Dino", "email": "dino@mail.com", "id": 4 }


Criar registro em Shell


Para criar um registro em Shell, realizamos um request do tipo POST para a URL contendo o endpoint /contacts, identificando os dados do objeto no parâmetro “-d”.

curl -i -X POST -H 'Content-Type: application/json' -d '{"name": "Dino", "email" : "dino@email.com"}' http://localhost/sistema/contacts


O retorno será um objeto com os dados.

Retorno
HTTP/1.1 200 OK {"status":"success","data":{"name":"Dino","email":"dino@email.com","id":5}}


Alterar registro em PHP


Para alterar um registro em PHP, realizamos um request do tipo PUT para a URL contendo o endpoint /contacts/<id>, identificando os dados para alteração do objeto no terceiro parâmetro.

  1. <?php
  2. require_once 'request.php';
  3. try
  4. {
  5.     $body = [];
  6.     $body['name']     = 'Dino Sauro';
  7.     $location 'http://localhost/sistema/contacts/3';
  8.     print_rrequest($location'PUT'$body) );
  9. }
  10. catch (Exception $e)
  11. {
  12.     echo 'Error: ' $e->getMessage();
  13. }
  14. ?>


O retorno será um objeto com os dados.

Retorno
stdClass Object ( [id] => 3 [name] => Dino Sauro )


Alterar registro em Javascript


Para alterar um registro em Javascript, realizamos um request do tipo PUT para a URL contendo o endpoint /contacts/<id>, identificando os dados para alteração do objeto no parâmetro data.

$.ajax({ type: 'PUT', contentType: 'application/json', url: 'http://localhost/sistema/contacts/3', data: JSON.stringify({ 'name': 'Dino Sauro', }), dataType: 'json', success: function (response) { console.log(response.data); } });


O retorno será um objeto com os dados.


Retorno
{ "id": "3", "name": "Dino Sauro" }


Alterar registro em Shell


Para alterar um registro em Shell, realizamos um request do tipo PUT para a URL contendo o endpoint /contacts/<id>, identificando os dados para alteração do objeto no parâmetro “-d”.

curl -i -X PUT -H 'Content-Type: application/json' -d '{"name": "Dino Sauro"}' http://localhost/sistema/contacts/3


O retorno será um objeto com os dados.


Retorno
HTTP/1.1 200 OK {"status":"success","data":{"id":"3","name":"Dino Sauro"}}


Excluir registro em PHP


Para excluir um registro em PHP, realizamos um request do tipo DELETE para a URL contendo o endpoint /contacts/<id>.

  1. <?php
  2. require_once 'request.php';
  3. try
  4. {
  5.     $location 'http://localhost/sistema/contacts/3';
  6.     print_rrequest($location'DELETE') );
  7. }
  8. catch (Exception $e)
  9. {
  10.     echo 'Error: ' $e->getMessage();
  11. }
  12. ?>


Excluir registro em Javascript



Para excluir um registro em Javascript, realizamos um request do tipo DELETE para a URL contendo o endpoint /contacts/<id>.

$.ajax({ type: 'DELETE', contentType: 'application/json', url: 'http://localhost/sistema/contacts/3', dataType: 'json', success: function (response) { console.log(response.data); } });


Excluir registro em Shell



Para excluir um registro em Shell, realizamos um request do tipo DELETE para a URL contendo o endpoint /contacts/<id>.
curl -i -X DELETE http://localhost/sistema/contacts/3



Retorno
{"status":"success","data":null}



Carregar vários registros em PHP



Para carregar vários registros em PHP, realizamos um request do tipo GET para a URL contendo o endpoint /contacts, identificando no terceiro parâmetro ordem, limit e filtros.

  1. <?php
  2. require_once 'request.php';
  3. try
  4. {
  5.     $body['limit'] = '3';
  6.     $body['order'] = 'name';
  7.     $body['direction'] = 'desc';
  8.     // $body['filters'] = [ ['id', '>', 1] ];
  9.     
  10.     $location 'http://localhost/sistema/contacts';
  11.     print_rrequest($location'GET'$body) );
  12. }
  13. catch (Exception $e)
  14. {
  15.     echo 'Error: ' $e->getMessage();
  16. }
  17. ?>


O retorno será um objeto com os dados.


Retorno
Array ( [0] => stdClass Object ( [name] => Mary [email] => mary@mary.com [number] => +55 (51) 1234-5678 [address] => Mary Street, 123, Philadephia [notes] => Good customer [id] => 1 ) [1] => stdClass Object ( [name] => John [email] => john@mail.com [number] => +55 (51) 1234-5678 [address] => Jon Street, 123, Philadelphia [notes] => Good customer [id] => 2 ) ...



Carregar vários registros em Javascript


Para carregar vários registros em Javascript, realizamos um request do tipo GET para a URL contendo o endpoint /contacts, identificando parâmetros como ordem, limit e filtros.

$.ajax({ type: 'GET', url: 'http://localhost/sistema/contacts', data: { 'order': 'name', 'direction': 'desc', 'limit': '3', 'filters' :[["id",">=",1],["id","<=","10"]] }, dataType: 'json', success: function (response) { console.log(response.data); } });


O retorno será um objeto com os dados.


Retorno

[ { "name": "Mary", "email": "mary@mary.com", "number": "+55 (51) 1234-5678", "address": "Mary Street, 123 Philadephia", "notes": "Good customer", "id": "1" }, { "name": "John", "email": "john@mail.com", "number": "+55 (51) 1234-5678", "address": "Jon Street, 123 Philadelphia", "notes": "Good customer", "id": "2" } ]


Carregar vários registros em Shell



Para carregar vários registros em Shell, realizamos um request do tipo GET para a URL contendo o endpoint /contacts, identificando no argumento “-d” parâmetros como ordem, limit e filtros.

curl -i -X GET -d '{"order": "name", "direction": "desc", "limit": 3}' http://localhost/sistema/contacts


Retorno

HTTP/1.1 200 OK {"status":"success","data":[{"name":"Mary","email":"mary@mary.com","number":"+55 (51) 1234-5678","address":"Mary Street, 123\r\nPhiladephia","notes":"Good customer","id":"1"},{"name":"John","email":"john@mail.com","number":"+55 (51) 1234-5678","address":"Jon Street, 123\r\nPhiladelphia","notes":"Good customer","id":"2"}]}



Excluir vários registros em PHP


Para excluir vários registros em PHP, realizamos um request do tipo DELETE para a URL contendo o endpoint /contacts, identificando no terceiro parâmetro os filtros.

  1. <?php
  2. require_once 'request.php';
  3. try
  4. {
  5.     $location 'http://localhost/sistema/contacts';
  6.     $body = [];
  7.     $body['filters'] = [ ['id''>'1], ['id''<''3']];
  8.     print_rrequest($location'DELETE'$body) );
  9. }
  10. catch (Exception $e)
  11. {
  12.     echo 'Error: ' $e->getMessage();
  13. }
  14. ?>



Excluir vários em Javascript



Para excluir vários registros em Javascipt, realizamos um request do tipo DELETE para a URL contendo o endpoint /contacts, identificando no parâmetro data, os filtros.

$.ajax({ type: 'DELETE', contentType: 'application/json', url: 'http://localhost/sistema/contacts', data: JSON.stringify({ 'filters' :[["id",">",5],["id","<","10"]] }), dataType: 'json', success: function (response) { console.log(response.data); } });


Excluir vários registros em Shell



Para excluir vários registros em Shell, realizamos um request do tipo DELETE para a URL contendo o endpoint /contacts, identificando no argumento “-d”, os filtros.

curl -i -X DELETE -d '{"filters":[["id",">",5],["id","<","10"]]}' http://localhost/sistema/contacts



Retorno
HTTP/1.1 200 OK {"status":"success","data":0}



Executando um método próprio



Nem sempre os métodos básicos (load, store, delete) são suficientes. Existem situações, onde é necessário disponibilizar um método personalizado com alguma regra de negócio diferenciada. Nestes casos, podemos criar um método próprio da classe de serviço. Neste caso, vamos criar um método chamado name() que retornará o nome do registro solicitado. Claro que isso não é necessário pois o GET já carrega o objeto inteiro, mas podemos realizar outras operações mais complexas também.


app/service/ContactRestService.php

  1. <?php
  2. class ContactRestService extends AdiantiRecordService
  3. {
  4.     const DATABASE      'contacts';
  5.     const ACTIVE_RECORD 'Contact';
  6.     
  7.     public function name$request )
  8.     {
  9.         TTransaction::open('contacts');
  10.         $name Contact::find($request['id'])->name;
  11.         TTransaction::close();
  12.         return $name;
  13.     }
  14. }
  15. ?>


No exemplo a seguir, vemos como consumir o método. Para tal, realizamos um request GET para a URL contendo o registro a ser manipulado /contacts/<id>/metodo.

  1. <?php
  2. require_once 'request.php';
  3. try
  4. {
  5.     $location 'http://localhost/sistema/contacts/1/name';
  6.     print_rrequest($location'GET') );
  7. }
  8. catch (Exception $e)
  9. {
  10.     echo 'Error: ' $e->getMessage();
  11. }
  12. ?>


Agora, em Javascript:
$.ajax({ type: 'GET', url: 'http://localhost/sistema/contacts/1/name', success: function (response) { console.log(response.data); } });


Agora, em Shell
curl -i -X GET http://localhost/sistema/contacts/1/name


Retorno
Mary


Curso completo Meu Negócio Pronto
Use para si, ou transforme em um negócio: Inclui aulas e códigos-fontes
Gestor de conteúdo (SITE) + Loja Virtual (E-Commerce) + Emissor de Notas para infoprodutos


Meu negócio pronto Quero me inscrever agora!

Comentários (5)


MG

Como implementar basic authentication?
WF

E se eu precisar mudar algo em algum das funções? Não consigo sobreescrever nenhuma delas sem usar direto a classe direto do adianti.
ML

Existe algum exemplo de como fazer as chamadas com GET com filtro, e POST em Typescript ?
FS

Olá, pessoal.
O arquivo .htaccess precisa ficar na mesma pasta do arquivo rest.php?
RA

Olá Pessoal, como eu altero um registro com json puro para o Adianti, enviado por exemplo do postman ou insomina. O serviço rest do adianti não é padrão json ?

Exemplo abaixo, verbo POST:
{ "class" : "ClientesService", "method": "store", "data": [{ "CLI_NOME": "NEW CLIENTE 25", "id": "25" } ] }


Retorno:
{ "status": "success", "data": { "id": 2497 } }


Não funciona, esta fazendo o insert e estou chamando o update (store) com id

o que tem de errado nesse request ?