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
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.
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.