Dev. Software/ PHP

Implementando REST com PHP

rest_sample

Não faz muito tempo que eu escrevi sobre REST aqui no blog, e no post eu prometi que iria continuar com o assunto implementando serviços REST em diversas linguagens PHP, Java, C++, Python e até mesmo em Javascript.

Se você não sabe o que é REST, antes de continuar lendo o post, aconselho você ler o post que escrevi sobre o assunto, assim você não fica boiando no assunto.

Configurando o ambiente

Quem não tem um ambiente local para testar com PHP, sugiro um software que eu utilizo localmente o XAMPP. É open-source e grátis.
Existem outros no mercado que também faz o mesmo, só que eu gosto do XAMPP por que é prático.

Implementando o REST

Para implementar o REST você pode utilziar diversas bibliotecas espalhadas por ai, tem várias publicações e projetos que te levam à um atalho mais rápido para criar tal mecanismo. As que eu achei mais fantásticas foram essas:

O que eu acho mais fantástico nessas implementações são a abstração, eles basicamente deixam você livre para fazer o que quiser, a curva de aprendizagem também é bem mole.

O que um difere do outro?

Alguns recursos extras, por exemplo o Guzzle oferece uma arquitetura de plug-ins, onde você pode implementar suporte já fora da caixa em Cache, Oauth, etc. Já o Slim não tem tudo isso, porém oferece uma API mais simples de se dar.

Nesse exemplo eu vou usar o Slim Framework, baixe ele direto do site, depois de baixar descompacte-o no diretório raiz do XAMPP (htdocs), para ser mais direto.

rest-php

Na imagem acima, você ver que eu deixei só o diretório Slim, o arquivo .htdocs e o index.php

[note color=”#005fff”]IMPORTANTE: O Arquivo de .htaccess existente no projeto tem as regras necessárias para criação de rotas das URLs necessárias, você precisa tê-lo para usar o Slim.[/note]

Ok, abra o arquivo index e você tem o seguinte conteúdo.

<?php
/**
 * Step 1: Require the Slim Framework
 *
 * If you are not using Composer, you need to require the
 * Slim Framework and register its PSR-0 autoloader.
 *
 * If you are using Composer, you can skip this step.
 */
require 'Slim/Slim.php';
 
\Slim\Slim::registerAutoloader();
 
/**
 * Step 2: Instantiate a Slim application
 *
 * This example instantiates a Slim application using
 * its default settings. However, you will usually configure
 * your Slim application now by passing an associative array
 * of setting names and values into the application constructor.
 */
$app = new \Slim\Slim();
 
/**
 * Step 3: Define the Slim application routes
 *
 * Here we define several Slim application routes that respond
 * to appropriate HTTP request methods. In this example, the second
 * argument for `Slim::get`, `Slim::post`, `Slim::put`, and `Slim::delete`
 * is an anonymous function.
 */
 
// GET route
$app->get('/', function () {
    $template = <<<EOT
<!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8"/>
            <title>Slim Framework for PHP 5</title>
            <style>
                html,body,div,span,object,iframe,
                h1,h2,h3,h4,h5,h6,p,blockquote,pre,
                abbr,address,cite,code,
                del,dfn,em,img,ins,kbd,q,samp,
                small,strong,sub,sup,var,
                b,i,
                dl,dt,dd,ol,ul,li,
                fieldset,form,label,legend,
                table,caption,tbody,tfoot,thead,tr,th,td,
                article,aside,canvas,details,figcaption,figure,
                footer,header,hgroup,menu,nav,section,summary,
                time,mark,audio,video{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent;}
                body{line-height:1;}
                article,aside,details,figcaption,figure,
                footer,header,hgroup,menu,nav,section{display:block;}
                nav ul{list-style:none;}
                blockquote,q{quotes:none;}
                blockquote:before,blockquote:after,
                q:before,q:after{content:'';content:none;}
                a{margin:0;padding:0;font-size:100%;vertical-align:baseline;background:transparent;}
                ins{background-color:#ff9;color:#000;text-decoration:none;}
                mark{background-color:#ff9;color:#000;font-style:italic;font-weight:bold;}
                del{text-decoration:line-through;}
                abbr[title],dfn[title]{border-bottom:1px dotted;cursor:help;}
                table{border-collapse:collapse;border-spacing:0;}
                hr{display:block;height:1px;border:0;border-top:1px solid #cccccc;margin:1em 0;padding:0;}
                input,select{vertical-align:middle;}
                html{ background: #EDEDED; height: 100%; }
                body{background:#FFF;margin:0 auto;min-height:100%;padding:0 30px;width:440px;color:#666;font:14px/23px Arial,Verdana,sans-serif;}
                h1,h2,h3,p,ul,ol,form,section{margin:0 0 20px 0;}
                h1{color:#333;font-size:20px;}
                h2,h3{color:#333;font-size:14px;}
                h3{margin:0;font-size:12px;font-weight:bold;}
                ul,ol{list-style-position:inside;color:#999;}
                ul{list-style-type:square;}
                code,kbd{background:#EEE;border:1px solid #DDD;border:1px solid #DDD;border-radius:4px;-moz-border-radius:4px;-webkit-border-radius:4px;padding:0 4px;color:#666;font-size:12px;}
                pre{background:#EEE;border:1px solid #DDD;border-radius:4px;-moz-border-radius:4px;-webkit-border-radius:4px;padding:5px 10px;color:#666;font-size:12px;}
                pre code{background:transparent;border:none;padding:0;}
                a{color:#70a23e;}
                header{padding: 30px 0;text-align:center;}
            </style>
        </head>
        <body>
            <header>
                <a href="http://www.slimframework.com"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHIAAAA6CAYAAABs1g18AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABRhJREFUeNrsXY+VsjAMR98twAo6Ao4gI+gIOIKOgCPICDoCjCAjXFdgha+5C3dcv/QfFB5i8h5PD21Bfk3yS9L2VpGnlGW5kS9wJMTHNRxpmjYRy6SycgRvL18OeMQOTYQ8HvIoJKiiz43hgHkq1zvK/h6e/TyJQXeV/VyWBOSHA4C5RvtMAiCc4ZB9FPjgRI8+YuKcrySO515a1hoAY3nc4G2AH52BZsn+MjaAEwIJICKAIR889HljMCcyrR0QE4v/q/BVBQva7Q1tAczG18+x+PvIswHEAslLbfGrMZKiXEOMAMy6LwlisQCJLPFMfKdBtli5dIihRyH7A627Iaiq5sJ1ThP9xoIgSdWSNVIHYmrTQgOgRyRNqm/M5PnrFFopr3F6B41cd8whRUSufUBU5EL4U93AYRnIWimCIiSI1wAaAZpJ9bPnxx8eyI3Gt4QybwWa6T/BvbQECUMQFkhd3jSkPFgrxwcynuBaNT/u6eJIlbGOBWSNIUDFEIwPZFAtBfYrfeIOSRSXuUYCsprCXwUIZWYnmEhJFMIocMDWjn206c2EsGLCJd42aWSyBNMnHxLEq7niMrY2qyDbQUbqrrTbwUPtxN1ZZCitQV4ZSd6DyoxhmRD6OFjuRUS/KdLGRHYowJZaqYgjt9Lchmi3QYA/cXBsHK6VfWNR5jgA1DLhwfFe4HqfODBpINEECCLO47LT/+HSvSd/OCOgQ8qE0DbHQUBqpC4BkKMPYPkFY4iAJXhGAYr1qmaqQDbECCg5A2NMchzR567aA4xcRKclI405Bmt46vYD7/Gcjqfk6GP/kh1wovIDSHDfiAs/8bOCQ4cf4qMt7eH5Cucr3S0aWGFfjdLHD8EhCFvXQlSqRrY5UV2O9cfZtk77jUFMXeqzCEZqSK4ICkSin2tE12/3rbVcE41OBjBjBPSdJ1N5lfYQpIuhr8axnyIy5KvXmkYnw8VbcwtTNj7fDNCmT2kPQXA+bxpEXkB21HlnSQq0gD67jnfh5KavVJa/XQYEFSaagWwbgjNA+ywstLpEWTKgc5gwVpsyO1bTII+tA6B7BPS+0PiznuM9gPKsPVXbFdADMtwbJxSmkXWfRh6AZhyyzBjIHoDmnCGaMZAKjd5hyNJYCBGDOVcg28AXQ5atAVDO3c4dSALQnYblfa3M4kc/cyA7gMIUBQCTyl4kugIpy8yA7ACqK8Uwk30lIFGOEV3rPDAELwQkr/9YjkaCPDQhCcsrAYlF1v8W8jAEYeQDY7qn6tNGWudfq+YUEr6uq6FZzBpJMUfWFDatLHMCciw2mRC+k81qCCA1DzK4aUVfrJpxnloZWCPVnOgYy8L3GvKjE96HpweQoy7iwVQclVutLOEKJxA8gaRCjSzgNI2zhh3bQhzBCQQPIHGaHaUd96GJbZz3Smmjy16u6j3FuKyNxcBarxqWWfYFE0tVVO1Rl3t1Mb05V00MQCJ71YHpNaMcsjWAfkQvPPkaNC7LqTG7JAhGXTKYf+VDeXAX9IvURoAwtTFHvyYIxtnd5tPkywrPafcwbeSuGVwFau3b76NO7SHQrvqhfFE8kM0Wvpv8gVYiYBlxL+fW/34bgP6bIC7JR7YPDubcHCPzIp4+cum7U6NlhZgK7lua3KGLeFwE2m+HblDYWSHG2SAfINuwBBfxbJEIuWZbBH4fAExD7cvaGVyXyH0dhiAYc92z3ZDfUVv+jgb8HrHy7WVO/8BFcy9vuTz+nwADAGnOR39Yg/QkAAAAAElFTkSuQmCC" alt="Slim"/></a>
            </header>
            <h1>Welcome to Slim!</h1>
            <p>
                Congratulations! Your Slim application is running. If this is
                your first time using Slim, start with this <a href="http://www.slimframework.com/learn" target="_blank">"Hello World" Tutorial</a>.
            </p>
            <section>
                <h2>Get Started</h2>
                <ol>
                    <li>The application code is in <code>index.php</code></li>
                    <li>Read the <a href="http://docs.slimframework.com/" target="_blank">online documentation</a></li>
                    <li>Follow <a href="http://www.twitter.com/slimphp" target="_blank">@slimphp</a> on Twitter</li>
                </ol>
            </section>
            <section>
                <h2>Slim Framework Community</h2>
 
                <h3>Support Forum and Knowledge Base</h3>
                <p>
                    Visit the <a href="http://help.slimframework.com" target="_blank">Slim support forum and knowledge base</a>
                    to read announcements, chat with fellow Slim users, ask questions, help others, or show off your cool
                    Slim Framework apps.
                </p>
 
                <h3>Twitter</h3>
                <p>
                    Follow <a href="http://www.twitter.com/slimphp" target="_blank">@slimphp</a> on Twitter to receive the very latest news
                    and updates about the framework.
                </p>
            </section>
            <section style="padding-bottom: 20px">
                <h2>Slim Framework Extras</h2>
                <p>
                    Custom View classes for Smarty, Twig, Mustache, and other template
                    frameworks are available online in a separate repository.
                </p>
                <p><a href="https://github.com/codeguy/Slim-Extras" target="_blank">Browse the Extras Repository</a></p>
            </section>
        </body>
    </html>
EOT;
    echo $template;
});
 
// POST route
$app->post('/post', function () {
    echo 'This is a POST route';
});
 
// PUT route
$app->put('/put', function () {
    echo 'This is a PUT route';
});
 
// DELETE route
$app->delete('/delete', function () {
    echo 'This is a DELETE route';
});
 
/**
 * Step 4: Run the Slim application
 *
 * This method should be called last. This executes the Slim application
 * and returns the HTTP response to the HTTP client.
 */
$app->run();

Mude-o para isso aqui.

<?php
require 'Slim/Slim.php'; // chamando a biblioteca
 
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim(); // registrando e inicializando o objeto no servidor
 
 
// GET route
$app->get('/', function () {
    $template = <<<EOT
        <h1>Implementando REST com slim framework</h1>
EOT;
    echo $template;
});
 
// POST route
$app->post('/post', function () {
    echo 'This is a POST route';
});
 
// PUT route
$app->put('/put', function () {
    echo 'This is a PUT route';
});
 
// DELETE route
$app->delete('/delete', function () {
    echo 'This is a DELETE route';
});
 
$app->run();

O que eu fiz foi remover os comentários excessivos que tinha no arquivo e coloquei uma mensagem customizada para mostrar que roda tranquilamente.

Toda vez que você for implementar um novo método no Slim Framework, basta você definir que tipo de comportamento ele possui e a ação que ele irá fazer.

Por exemplo quero criar um novo método chamado calcular.

$app->post('/calcular/:metodo',function($metodo) use ($app){
 
        $request = $app->request();
        $body = $request->post();
 
    switch($metodo){
            case 'somar':
                        echo $body['A'] + $body['B'];
            break;
            case 'dividir':
                        echo $body['A'] / $body['B'];
            break;
            case 'multiplicar':
                        echo $body['A'] * $body['B'];
            break;
            case 'diminuir':
                        echo $body['A'] - $body['B'];
            break;
    }
});

Eu posso usar as URIs com os métodos (/put, /post, /get, /delete).

E para testar meu serviço de REST como faço? Bom, você pode usar o cURL ou usar uma GUI para facilitar o processo, já que eu estou utilizando o navegador, eu vou adicionar uma extensão para o Google Chrome fazer isso. POSTMAN para nos salvar.

rest-gui

Na Webstore do google procure pelo POST MAN e você acha ele fácil, basta clicar em instalar e começar a testar.

rest-gui-demo

Coloco a URL, passo os parametros e voilá! Meu serviço de REST está implementado.

E como fica a requisição do servidor na aba de acesso? Vamos ver!

rest-php-call

Perfeito, eu posso criar vários serviços Web sem precisar escrever uma interface própria para testar, não existe mais desculpas esfarrapadas de esperar o Designer terminar a conversão de PSD para HTML/CSS para você começar a testar os serviços.

Esse é um belo exemplo simples de como implementar um serviço de REST. Agora vamos para um exemplo prático, digo mais completo.

Nesse exemplo usei o SQlite 3 para persistir os dados, você pode usar o que você quiser para persistência em PHP, o Slim não implica o uso de nenhum, já que dentro de suas chaves você pode escrever o que quiser.

[note color=”#007bff”]SQLite 3 só é suportado no PHP 5.4 em diante. Versões anteriores você pode usar o SQLite 2. Para saber qual versão que você tem use o php_info();[/note]

É bem simples o serviço de REST com uma API bem simplificada. O código abaixo contém as seguintes rotas que usaremos para o serviço.

  • GET /preload-inicial – Uso ele só 1 vez para carregar com dados falsos para ter algo para mostrar
  • GET /backup – Faz backup do banco
  • GET /clientes – Lista todos os clientes
  • GET /compras – Lista todas as compras do site
  • GET /compras/:id – Lista todas as compras de um cliente especifico pelo ID
  • PUT /cliente – Adicionar novos clientes
  • PUT /compra – Adicionar novas compras
  • POST /cliente/:id – Atualiza o cliente pelo ID
  • POST /compra/:id – Atualiza uma compra pelo ID
<?php
require 'Slim/Slim.php';
 
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
 
$response =array();
$db = new SQLite3('coisas.db');
 
 
// Uso essa função só para gerar dados fakes para ser usado no sistema
$app->get('/preload-inicial', function () use ($db,$response)
{       $value = rand(5,99);
        $db->exec('CREATE TABLE IF NOT EXISTS clientes(id INTEGER PRIMARY KEY AUTOINCREMENT, nome TEXT);');
        $db->exec('CREATE TABLE IF NOT EXISTS compras(id INTEGER PRIMARY KEY, cliente_id INTEGER, valor INTEGER, compra_realizada DATETIME);');
        $db->query("INSERT OR IGNORE INTO clientes (nome) VALUES ('Igor Costa');");
        $db->query("INSERT OR IGNORE INTO clientes (nome) VALUES ('Elly Costa');");
        $db->query("INSERT OR IGNORE INTO clientes (nome) VALUES ('Leonardo Sobral');");
        $db->query("INSERT OR IGNORE INTO clientes (nome) VALUES ('Francisco Brianezi');");
        for($i=1;$i<=4;$i++){
            $db->query("INSERT INTO compras (valor,cliente_id,compra_realizada) VALUES ($value,$i,datetime());");
        }
 
});
// adicionar cliente
$app->put('/cliente', function () use($db,$response,$app) {
    $request = $app->request();
    $cliente = $request->put('nome');
    $response =$db->exec("INSERT INTO clientes (nome) VALUES ('$cliente');");
    echo $response;
});
// adicionar nova compra
$app->put('/compra', function () use($db,$response,$app) {
    $request = $app->request();
    $valor = $request->put('valor');
    $cliente = $request->put('cliente_id');
    $response = $db->query("INSERT INTO compras (valor,cliente_id,compra_realizada) VALUES ($valor,$cliente,datetime());");
    echo $response;
});
 
 
// Ediar cliente
 
$app->post('/cliente/:id',function($id) use($db,$response,$app){
    $request = $app->request();
    $nome = $request->post('nome');
    $response = $db->exec("UPDATE clientes SET nome='$nome' WHERE id=$id;");
    echo json_encode($response);
});
 
$app->post('/compra/:id',function($id) use($db,$response,$app){
    $request = $app->request();
    $valor = $request->post('valor');
    $cliente = $request->post('cliente_id');
    $response = $db->exec("UPDATE compras SET valor='$valor', cliente_id='$cliente' WHERE id=$id;");
    echo json_encode($response);
});
 
// lista os clientes
$app->get('/clientes',function()use ($db,$response,$app){
 
   $app->contentType('application/json');
   $tarefas = $db->query("SELECT * FROM clientes");
        while ($row = $tarefas->fetchArray(SQLITE3_ASSOC)) {
            array_push($response,$row);
        }
      echo json_encode($response);
 
});
// lista todas as compras
$app->get('/compras',function() use($db,$response,$app){
   $app->contentType('application/json');
   $tarefas = $db->query("SELECT clientes.id,clientes.nome,COUNT(*) as total_compras
                          FROM compras INNER JOIN clientes ON compras.cliente_id = clientes.id 
                          GROUP BY clientes.nome ORDER BY clientes.nome ASC");
        while ($row = $tarefas->fetchArray(SQLITE3_ASSOC)) {
            array_push($response,$row);
        }
      echo json_encode($response);
 
});
// lista todas as compras por id do cliente
$app->get('/compras/:id',function($id) use ($db,$response){
 
    $tarefas = $db->query("SELECT * FROM compras INNER JOIN clientes 
        ON compras.cliente_id = clientes.id  WHERE clientes.id = $id");
        while ($row = $tarefas->fetchArray(SQLITE3_ASSOC)) {
            array_push($response,$row);
        }
      echo json_encode($response); 
});
$app->get('/backup',function() use($app){
    $date = date("Y-m-d");
    exec('mkdir backups');
    $file = 'backups/backup-'.$date . '.sql';
    exec("sqlite3 coisas.db .dump > ".$file);
    echo readfile($file);
});
 
// Deleta cliente
$app->delete('/deleta/cliente/:id', function ($id) use ($db,$response,$app) {
 
    // para remover compras existentes do cliente
    $db->exec("DELETE FROM compras WHERE cliente_id=$id;");
    $response =$db->query("DELETE FROM clientes WHERE id=$id;");
    echo $response; 
});
// Deleta compra
$app->delete('/deleta/compra/:id', function ($id) {
    $response =$db->query("DELETE FROM compras WHERE id=$id;");
    echo $response; 
});
 
$app->run();

Para consumir esse serviço você pode usar a seguinte interface.

rest-gui-php-demo

Agora você já sabe como implementar um serviço em RESTful com PHP usando o Slim Framework. Na próxima competição que você participar use algo assim, é hiper rápido e você não gasta mais que 1 hora para implementar.

O uso do SQLite eu aconselho para coisas bem simples, listas simples e pouco à médio volume de dados. Não queria criar um ERP com SQLite que você está perdendo seu tempo.

Para maiores detalhes sobre o Slim Framework, visite a documentação do projeto. É simples e bem intuitiva.

O código fonte está disponível também no Github.

2 thoughts on “Implementando REST com PHP

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios são marcados com *