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. // define o critério
  13. $criteria = new TCriteria;
  14. $criteria->add(new TFilter('id', '>=', $request['from']));
  15. $criteria->add(new TFilter('id', '<=', $request['to']));
  16. // carrega os produtos
  17. $all = Product::getObjects( $criteria );
  18. foreach ($all as $product)
  19. {
  20. $response[] = $product->toArray();
  21. }
  22. TTransaction::close();
  23. return $response;
  24. }
  25. }
  26. ?>



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. // aqui implementar mecanismo de controle !!
  12. if (!in_array($class, array('ProductService')))
  13. {
  14. return json_encode( array('status' => 'error',
  15. 'data' => _t('Permission denied')));
  16. }
  17. try
  18. {
  19. if (class_exists($class))
  20. {
  21. if (method_exists($class, $method))
  22. {
  23. $rf = new ReflectionMethod($class, $method);
  24. if ($rf->isStatic())
  25. {
  26. $response = call_user_func(array($class, $method), $request);
  27. }
  28. else
  29. {
  30. $response = call_user_func(array(new $class($request), $method), $request);
  31. }
  32. return json_encode( array('status' => 'success', 'data' => $response));
  33. }
  34. else
  35. {
  36. $error_message = TAdiantiCoreTranslator::translate('Method ^1 not found', "$class::$method");
  37. return json_encode( array('status' => 'error', 'data' => $error_message));
  38. }
  39. }
  40. else
  41. {
  42. $error_message = TAdiantiCoreTranslator::translate('Class ^1 not found', $class);
  43. return json_encode( array('status' => 'error', 'data' => $error_message));
  44. }
  45. }
  46. catch (Exception $e)
  47. {
  48. return json_encode( array('status' => 'error', 'data' => $e->getMessage()));
  49. }
  50. }
  51. }
  52. print AdiantiRestServer::run($_REQUEST);
  53. ?>



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_dump( json_decode( file_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 Dominando o Adianti Framework

O material mais completo de treinamento do Framework.
Curso em vídeo aulas + Livro completo + Códigos fontes do projeto ERPHouse.
Conteúdo Atualizado!


Dominando o Adianti Framework 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. //Inicia a transacao com o banco 'pg_ceres'.
  21. TTransaction::open('ead_content');
  22. //Instancia um repositorio.
  23. $repository = new TRepository('Modulo');
  24. //Cria um criterio novo.
  25. $criteria = new TCriteria();
  26. //Filtra pelo servidor.
  27. $criteria->setProperty('order', 'id');
  28. //Carrega os objetos de acordo com o criterio.
  29. $modulo = $repository->load($criteria);
  30. if ($modulo) {
  31. $response[$success_tag] = 1;
  32. $response["modulo"] = array();
  33. //Para cada municipio usuario existente
  34. foreach ($modulo as $modulos) {
  35. //Adiciona esse array.
  36. array_push($response["modulo"], $modulos->toArray());
  37. }
  38. } else {
  39. //Municipio nao encontrado.
  40. $response[$success_tag] = 2;
  41. }
  42. //Exibe o JSON.
  43. echo json_encode($response);
  44. //Finaliza a transacao
  45. TTransaction::close();
  46. }
  47. }
  48. ModuloWebservice::getAll();
  49. ?>
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>