Disponibilizando Web Services pelo Adianti Framework com REST Durante o desenvolvimento de um sistema, é comum termos de disponibilizar algumas de suas rotinas para que estas sejam executadas por aplicativos externos. O caminho mais utilizado para tal é por meio de Web Services, e REST é um dos meios para se obter isto. Imagine que você desenvolveu todo um sistema que controla produtos, e agora precisa que outros sistemas possam consultar i...
PD
Disponibilizando Web Services pelo Adianti Framework com REST  
Fechado
Durante o desenvolvimento de um sistema, é comum termos de disponibilizar algumas de suas rotinas para que estas sejam executadas por aplicativos externos. O caminho mais utilizado para tal é por meio de Web Services, e REST é um dos meios para se obter isto. Imagine que você desenvolveu todo um sistema que controla produtos, e agora precisa que outros sistemas possam consultar informações a respeito destes produtos. Neste artigo veremos como disponibilizar métodos criados no Adianti Framework por meio de Web Services. Neste artigo, trabalharemos com a classe de Produtos, e criaremos um Web Service para retornar X produtos, sendo a partir de um intervalo definido (from, to).

Bom, em primeiro lugar, provavelmente você já tem uma série de classes de modelo representando suas tabelas na pasta app/model. Junto ao tutor, temos por exemplo a classe Product. Agora, queremos criar um Web Service para retornar X produtos. Para tal, precisamos criar uma classe de serviço. Uma classe de serviço age criando uma camada que interage com uma funcionalidade interna da aplicação e expõe esta funcionalidade para o mundo externo. Neste caso, vamos chamar a classe de ProductService e salvar em app/service/ProductService.php. Veja que a classe em questão, utiliza a classe Product, já existente em app/model/Product.php, e também usa a conexão "samples", existente em app/config/samples.ini

A classe ProductService terá o método getBetween() que retornará todos os produtos cujo ID está entre dois valores informados. Para tal, este método receberá o request HTTP como um parâmetro (array) com cada um dos parâmetros da chamada do Web Service. Neste exemplo, estes parâmetros identificam o código inicial (['from']) e final (['to']) dos produtos a serem obtidos.

app/service/ProductService.php
  1. <?php
  2. class ProductService
  3. {
  4.     /**
  5.      * Retorna todos produtos entre $from e $to
  6.      * @param $request HTTP request
  7.      */
  8.     public static function getBetween$request )
  9.     {
  10.         TTransaction::open('samples');
  11.         $response = array();
  12.         
  13.         // define o critério
  14.         $criteria = new TCriteria;
  15.         $criteria->add(new TFilter('id''>='$request['from']));
  16.         $criteria->add(new TFilter('id''<='$request['to']));
  17.         
  18.         // carrega os produtos
  19.         $all Product::getObjects$criteria );
  20.         foreach ($all as $product)
  21.         {
  22.             $response[] = $product->toArray();
  23.         }
  24.         TTransaction::close();
  25.         return $response;
  26.     }
  27. }
  28. ?>



O próximo passo é habilitar um servidor REST no Adianti Framework. Para tal, basta salvarmos o arquivo a seguir no diretório raíz da aplicação com o nome de rest.php. Este script NÃO FAZ PARTE da instalação default do framework por questões de segurança. 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).

Não abordaremos aqui como adicionar segurança à chamada REST, mas uma das formas, é passando uma chave de segurança ou utilizar Token-Based Authorization. Por enquanto, faremos apenas um filtro para permitir somente algumas classes (in_array).

/rest.php
  1. <?php
  2. // initialization script
  3. require_once 'init.php';
  4. class AdiantiRestServer
  5. {
  6.     public static function run($request)
  7.     {
  8.         $class   = isset($request['class']) ? $request['class']   : '';
  9.         $method  = isset($request['method']) ? $request['method'] : '';
  10.         $response NULL;
  11.         
  12.         // aqui implementar mecanismo de controle !!
  13.         if (!in_array($class, array('ProductService')))
  14.         {
  15.             return json_encode( array('status' => 'error',
  16.                                       'data'   => _t('Permission denied')));
  17.         }
  18.         
  19.         try
  20.         {
  21.             if (class_exists($class))
  22.             {
  23.                 if (method_exists($class$method))
  24.                 {
  25.                     $rf = new ReflectionMethod($class$method);
  26.                     if ($rf->isStatic())
  27.                     {
  28.                         $response call_user_func(array($class$method), $request);
  29.                     }
  30.                     else
  31.                     {
  32.                         $response call_user_func(array(new $class($request), $method), $request);
  33.                     }
  34.                     return json_encode( array('status' => 'success''data' => $response));
  35.                 }
  36.                 else
  37.                 {
  38.                     $error_message TAdiantiCoreTranslator::translate('Method ^1 not found'"$class::$method");
  39.                     return json_encode( array('status' => 'error''data' => $error_message));
  40.                 }
  41.             }
  42.             else
  43.             {
  44.                 $error_message TAdiantiCoreTranslator::translate('Class ^1 not found'$class);
  45.                 return json_encode( array('status' => 'error''data' => $error_message));
  46.             }
  47.         }
  48.         catch (Exception $e)
  49.         {
  50.             return json_encode( array('status' => 'error''data' => $e->getMessage()));
  51.         }
  52.     }
  53. }
  54. print AdiantiRestServer::run($_REQUEST);
  55. ?>



Agora que já temos a classe de serviço criada, basta invocarmos o Web Service pela linha de comando. Neste caso, basta copiarmos este trecho de arquivo e salvarmos com um nome qualquer (ex: rest_client.php), e executarmos ele pela linha de comando. Antes, lembre de substituir a variável location pelo caminho de sua aplicação

rest_client.php
  1. <?php
  2. $location 'http://www.meusistema.local/rest.php';
  3. $parameters = array();
  4. $parameters['class'] = 'ProductService';
  5. $parameters['method'] = 'getBetween';
  6. $parameters['from'] = '1';
  7. $parameters['to'] = '4';
  8. $url $location '?' http_build_query($parameters);
  9. var_dumpjson_decodefile_get_contents($url) ) );
  10. ?>


php5 rest_client.php


Pronto, você obterá como resultado os produtos 1 a 4 na forma de um array retornado pelo serviço.


Você também poderá fazer uma chamada Javascript, dessa maneira:
$.ajax({ type: 'GET', url: 'http://www.meusistema.local/rest.php', data: { 'class': 'ProductService', 'method': 'getBetween', 'from': '1', 'to': '4' }, dataType: 'json', success: function (response) { console.log(response.data); } });


PS: Ao criarmos uma camada específica para serviços (ProductService), desoneramos a classe de modelo (ProductService), e também evitamos de colocar lá chamadas para bibliotecas externas, o que não é recomendado para uma camada de modelo.

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 (6)


JM

Olá Pablo

Necessitei consumir alguns dados do sistema que desenvolvi com o Adianti framework, utilizei esta forma abaixo para gerar o JSON que é consumido pelo aplicativo móvel em Android.

Criei o diretório chamado service coloquei dentro do diretório app, ficando app/service/nomearquivo.class.php

Deu certo estou utilizando como uma aplicação backend.

Obrigado tbm pela sua dica.

  1. <?php
  2. //ini_set('display_errors', 1);
  3. //ini_set('display_startup_erros', 1);
  4. //error_reporting(E_ALL);
  5. chdir('../../');
  6. require_once 'init.php';
  7. header('Content-Type: application/json; charset=utf-8');
  8. use Adianti\Database\TTransaction;
  9. use Adianti\Database\TRepository;
  10. use Adianti\Database\TCriteria;
  11. //use Adianti\Database\TFilter;
  12. /*
  13.  * Classe ModuloWebservice
  14.  * Autor: Jackson Meires
  15.  * Data: 11/02/2016 
  16.  */
  17. class ModuloWebservice {
  18.     //Retorna os municipios que o usuario esta dando assistencia.
  19.     static public function getAll() {
  20.  
  21.         //Inicia a transacao com o banco 'pg_ceres'.
  22.         TTransaction::open('ead_content');
  23.         //Instancia um repositorio.
  24.         $repository = new TRepository('Modulo');
  25.         //Cria um criterio novo.
  26.         $criteria = new TCriteria();
  27.         //Filtra pelo servidor.
  28.         $criteria->setProperty('order''id');
  29.         
  30.         //Carrega os objetos de acordo com o criterio.
  31.         $modulo $repository->load($criteria);
  32.         if ($modulo) {
  33.             $response[$success_tag] = 1;
  34.             $response["modulo"] = array();
  35.             //Para cada municipio usuario existente
  36.             foreach ($modulo as $modulos) {
  37.                 //Adiciona esse array.
  38.                 array_push($response["modulo"], $modulos->toArray());
  39.             }
  40.         } else {
  41.             //Municipio nao encontrado.
  42.             $response[$success_tag] = 2;
  43.         }
  44.         //Exibe o JSON.
  45.         echo json_encode($response);
  46.         //Finaliza a transacao
  47.         TTransaction::close();
  48.      
  49.     }
  50. }
  51. ModuloWebservice::getAll();
  52. ?>
PL

Isso resolveu meu problema de impressão de etiquetas.
Delphi + FastReport consumindo um serviço de Dados do Adianti.

Parabéns, Ótimo Artigo.
CS

Boa tarde,
Pessoal estou com dificuldades, até aqui entendi, mais peguei um processo que exige autenticação e não estou conseguindo fazer... abaixo segue trecho do documento do sistema:

"Para garantir a segurança e privacidade dos dados dos clientes que optarem por utilizar a API de Integração, além de disponibilizar os métodos consumíveis através de protocolo HTTPS, foram definidas formas de autenticação para o cliente, mantendo assim a privacidade dos dados. Para que esta autenticação seja possível no Header de cada requisição realizada pelo modulo do cliente a API de Integração devem constar os seguintes cabeçalhos:

Authorization-Token: 123456789
User: teste@email.com.br
App: xyz

como implemento isso nesse exemplo rest_client.php ?
EJ

Pablo, tudo bem, como seria forma correta de fazer um post passando Json para classe para inserir no banco ?, com pego isso cabeçalho ?
RK

Carlos e Eduardo,

O php tem a função "get_headers" (php.net/manual/pt_BR/function.get-headers.php), com ela vocês podem ler os cabeçalhos da requisição e implementar a camada de segurança.
FC

Bom dia Pablo

Fiz o exemplo acima descrito e funcionou a partir do script PHP, listou os usuarios do sistema mas precisei acessar estes mesmos dados pelo android e apresenta erro 404.
Você poderia me explicar alguma forma de acessar este ws rest pelo android? o meu script está mostrando erro 404 e nesta linha
Type type = new TypeToken<ArrayList<Usuario>>(){}.getType();

no android criei a URL
http://999.999.999.999/rest_usu?class=UsuariosService&getlAll


Caso possa me ajudar agradeço.

Flávio Cardoso
</Usuario>