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
<?phpclass ProductService{    /**     * Retorna todos produtos entre $from e $to     * @param $request HTTP request     */    public static function getBetween( $request )    {        TTransaction::open('samples');        $response = array();                // define o critério        $criteria = new TCriteria;        $criteria->add(new TFilter('id', '>=', $request['from']));        $criteria->add(new TFilter('id', '<=', $request['to']));                // carrega os produtos        $all = Product::getObjects( $criteria );        foreach ($all as $product)        {            $response[] = $product->toArray();        }        TTransaction::close();        return $response;    }}?>



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
<?php// initialization scriptrequire_once 'init.php';class AdiantiRestServer{    public static function run($request)    {        $class   = isset($request['class']) ? $request['class']   : '';        $method  = isset($request['method']) ? $request['method'] : '';        $response = NULL;                // aqui implementar mecanismo de controle !!        if (!in_array($class, array('ProductService')))        {            return json_encode( array('status' => 'error',                                      'data'   => _t('Permission denied')));        }                try        {            if (class_exists($class))            {                if (method_exists($class, $method))                {                    $rf = new ReflectionMethod($class, $method);                    if ($rf->isStatic())                    {                        $response = call_user_func(array($class, $method), $request);                    }                    else                    {                        $response = call_user_func(array(new $class($request), $method), $request);                    }                    return json_encode( array('status' => 'success', 'data' => $response));                }                else                {                    $error_message = TAdiantiCoreTranslator::translate('Method ^1 not found', "$class::$method");                    return json_encode( array('status' => 'error', 'data' => $error_message));                }            }            else            {                $error_message = TAdiantiCoreTranslator::translate('Class ^1 not found', $class);                return json_encode( array('status' => 'error', 'data' => $error_message));            }        }        catch (Exception $e)        {            return json_encode( array('status' => 'error', 'data' => $e->getMessage()));        }    }}print AdiantiRestServer::run($_REQUEST);?>



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
<?php$location = 'http://www.meusistema.local/rest.php';$parameters = array();$parameters['class'] = 'ProductService';$parameters['method'] = 'getBetween';$parameters['from'] = '1';$parameters['to'] = '4';$url = $location . '?' . http_build_query($parameters);var_dump( json_decode( file_get_contents($url) ) );?>


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.

<?php//ini_set('display_errors', 1);//ini_set('display_startup_erros', 1);//error_reporting(E_ALL);chdir('../../');require_once 'init.php';header('Content-Type: application/json; charset=utf-8');use Adianti\Database\TTransaction;use Adianti\Database\TRepository;use Adianti\Database\TCriteria;//use Adianti\Database\TFilter;/* * Classe ModuloWebservice * Autor: Jackson Meires * Data: 11/02/2016  */class ModuloWebservice {    //Retorna os municipios que o usuario esta dando assistencia.    static public function getAll() {         //Inicia a transacao com o banco 'pg_ceres'.        TTransaction::open('ead_content');        //Instancia um repositorio.        $repository = new TRepository('Modulo');        //Cria um criterio novo.        $criteria = new TCriteria();        //Filtra pelo servidor.        $criteria->setProperty('order', 'id');                //Carrega os objetos de acordo com o criterio.        $modulo = $repository->load($criteria);        if ($modulo) {            $response[$success_tag] = 1;            $response["modulo"] = array();            //Para cada municipio usuario existente            foreach ($modulo as $modulos) {                //Adiciona esse array.                array_push($response["modulo"], $modulos->toArray());            }        } else {            //Municipio nao encontrado.            $response[$success_tag] = 2;        }        //Exibe o JSON.        echo json_encode($response);        //Finaliza a transacao        TTransaction::close();         }}ModuloWebservice::getAll();?>
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>