Criando APIs usando o micro-framework Respect
-
Upload
ivan-rosolen-phpsp -
Category
Documents
-
view
4.171 -
download
13
description
Transcript of Criando APIs usando o micro-framework Respect
Criando APIs usando o micro-framework
RespectTuesday, July 2, 13
Ivan RosolenGraduado em sistemas de InformaçãoPós-graduado em Gerência de Projetos
Desenvolvedor a 10+ anosAutor de vários PHPT (testes para o PHP)
Gerente de Projetos na Arizona
Tuesday, July 2, 13
API
Tuesday, July 2, 13
O que é?
Tuesday, July 2, 13
"[] conjunto de rotinas e padrões estabelecidos por um software para a utilização das suas funcionalidades por aplicativos que não pretendem envolver-se em detalhes da implementação do software, mas apenas usar seus serviços []"
Wikipedia
Tuesday, July 2, 13
Porque criar uma API?
Tuesday, July 2, 13
Múltiplas interfaces (web, mobile, CLI)
Tuesday, July 2, 13
Integração com outros serviços da sua empresa
Venda de recursos e dados
Tuesday, July 2, 13
EXEMPLO
Tuesday, July 2, 13
RestBeer
Tuesday, July 2, 13
API de informações de Ceveja!
http://restbeer.local/cervejas/
http://restbeer.local/cervejas/Guinness
http://restbeer.local/cervejas/Heineken
http://restbeer.local/cervejas/Skol
Tuesday, July 2, 13
RESPECT
Tuesday, July 2, 13
Micro-framework para PHP 5.3+ construido por Alexandre Gaigalas
(alganet) e comunidade
Tuesday, July 2, 13
Instalando
Tuesday, July 2, 13
vhost (apache)
ServerName "restbeer.local" DocumentRoot "/caminho_do_projeto/restBeer/"
<Directory "/caminho_do_projeto/restBeer"> Options -Indexes FollowSymLinks AllowOverride All Order Allow,Deny Allow from all</Directory>
CustomLog /caminho_dos_logs/restbeer-access_log combined ErrorLog /caminho_dos_logs/restbeer-error_log
Tuesday, July 2, 13
/etc/hosts
127.0.0.1 restbeer.local
Tuesday, July 2, 13
.htaccess
RewriteEngine On
# Redirect all requests not pointing at an actual file to index.phpRewriteCond %{REQUEST_FILENAME} !-fRewriteRule . index.php [L]
Tuesday, July 2, 13
composer.json
{ "name": "RestBeer", "authors": [ { "name": "Ivan Rosolen", "email": "[email protected]" } ], "require": { "respect/rest": "0.5.x", "respect/relational": "0.5.x", "respect/config": "0.3.x", "respect/validation": "0.4.x" }}
Tuesday, July 2, 13
Instalando dependências
curl -s http://getcomposer.org/installer | php
php composer.phar install
Tuesday, July 2, 13
Respect/Config
Tuesday, July 2, 13
‣ Apenas arquivos .INI
‣ Usa o mesmo parser nativo e rápido do php.ini
‣ Extende o arquivo .INI com seu próprio “dialeto”
‣ Implementa lazy loading para instâncias de objeto
‣ Arquivo config.ini:
db_name = "restbeer.db"dsn = "sqlite:[db_name]"
‣ Utilização:
use Respect\Config\Container;
/** * Ler arquivo de configuração */$config = new Container('config.ini');
echo $config->dsn; // sqlite:restbeer.db
‣ http://github.com/Respect/Config
Tuesday, July 2, 13
Respect/Relational
Tuesday, July 2, 13
‣ Quase zero de configuracão
‣ Fluent interface: $mapper->author[7]->fetch();
‣ Se adapta a diferentes databases
‣ Registros são tratados como Plain Data Object
‣ Dependência: Respect\Data (http://github.com/Respect/Data)
‣ Utilização:
use Respect\Relational\Mapper;
// Criar instância PDO com o SQLite// diretório precisa ter permissão de escrita também o.O$mapper = new Mapper(new PDO('sqlite:database.sq3'));
// buscar todos os autores$authors = $mapper->author->fetchAll();
// gravar um autor$obj = new stdClass;$obj->name = 'Ivan Rosolen';$mapper->author->persist($obj);$mapper->flush();
‣ http://github.com/Respect/Relational
Tuesday, July 2, 13
Respect/Validation
Tuesday, July 2, 13
‣ Fluent/Chained interface: v::numeric()->positive()->between(1, 256)->validate($num)
‣ Mais de 30 validadores testados
‣ Possibilidade de utilizar validadores Zend/Symfony se instalados
‣ Utilização:
use Respect\Validation\Validator as v;
// validar número simples$number = 123;v::numeric()->validate($number); //true
// validar em cadeia$v = v::arr() // validar se é array ->key('nome', $rule = v::alnum()->notEmpty()->noWhitespace()) // validar a key 'nome' ->key('estilo', $rule) // utilizando a mesma regra da key de cima ->validate($_POST['cerveja']);
// zend validator$hostnameValidator = v::zend('Hostname')->assert('google.com');
// symfony validator$timeValidator = v::sf('Time')->assert('22:00:01');
‣ https://github.com/Respect/Validation
Tuesday, July 2, 13
Respect/Router
Tuesday, July 2, 13
‣ Thin and lightweight controller para aplicações RESTful e APIs
‣ Curva de aprendizado pequena
‣ Ótima documentação em português: http://www.cssexperts.net/respect-rest-docs-br/
‣ Utilização:
use Respect\Rest\Router;
// Criar instância do router$router = new Router; // raiz http://example.com/
// instância para trabalhar em uma subpasta$router = new Router('/pasta'); // raiz http://example.com/pasta
// Olá mundo$router->get('/', function() { return 'Hello World';});
‣ https://github.com/Respect/Rest
Tuesday, July 2, 13
Começando o projeto
Tuesday, July 2, 13
// autoload do composerrequire 'vendor/autoload.php'; use Respect\Rest\Router;use Respect\Config\Container;use Respect\Validation\Validator as v;use Respect\Relational\Mapper;use Respect\Data\Collections\Collection;
/** * Ler arquivo de configuração */$config = new Container('config.ini');
/** * Criar instância PDO com o SQLite usando as configs */// diretório precisa ter permissão de escrita também$mapper = new Mapper(new PDO($config->dsn));
// Criar instância do router$router = new Router(); /** * Rota para qualquer tipo de request (any) */$router->any('/', function () { return 'RestBeer!';});
Tuesday, July 2, 13
Buscar cervejas
Tuesday, July 2, 13
$router->get('/cervejas/*', function ($nome) use ($mapper) {
if ( !isset($nome) ) { $cervejas = $mapper->cervejas->fetchAll(); header('HTTP/1.1 200 Ok'); return $cervejas; }
$nome = filter_var( $nome, FILTER_SANITIZE_FULL_SPECIAL_CHARS );
if ( v::not(v::alnum()->notEmpty())->validate($nome) ) { header('HTTP/1.1 404 Not Found'); return 'Não encontrada'; }
$cerveja = $mapper->cervejas(array( 'nome' => $nome ))->fetch();
// BONUS - podemos buscar por id também // $cerveja = $mapper->cervejas[$id]->fetch();
if ( !$cerveja ) { header('HTTP/1.1 404 Not Found'); return 'Não encontrada'; }
header('HTTP/1.1 200 Ok'); return $cerveja;});
Tuesday, July 2, 13
Cadastrar uma cerveja
Tuesday, July 2, 13
$router->post('/cervejas', function () use ($mapper,$cervejas) { if ( !isset($_POST) || !isset($_POST['cerveja']) || v::not(v::arr())->validate($_POST['cerveja']) ) { header('HTTP/1.1 400 Bad Request'); return 'Faltam parâmetros'; }
$validation = v::arr() ->key('nome', $rule = v::alnum()->notEmpty()->noWhitespace()) ->key('estilo', $rule) ->validate($_POST['cerveja']); if ( !$validation ) { header('HTTP/1.1 400 Bad Request'); return 'Faltam parâmetros'; }
$cerveja = new stdClass(); $cerveja->nome = filter_var($_POST['cerveja']['nome'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); $cerveja->estilo = filter_var($_POST['cerveja']['estilo'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$check = $mapper->cervejas(array( 'nome' => $cerveja->nome ))->fetch(); if ( $check ) { header('HTTP/1.1 409 Conflict'); return 'Cerveja já existe no sistema'; }
$mapper->cervejas->persist($cerveja); $mapper->flush();
if ( !isset($cerveja->id) || empty($cerveja->id) ) { header('HTTP/1.1 500 Internal Server Error'); return 'Erro ao inserir cerveja'; } header('HTTP/1.1 201 Created'); return 'Cerveja criada'; });
Tuesday, July 2, 13
Alterar uma cerveja
Tuesday, July 2, 13
$router->put('/cervejas/*', function ($nome) use ($mapper) {
parse_str(file_get_contents('php://input'), $data);
if ( !isset($data) || !isset($data['cerveja']) || v::not(v::arr())->validate($data['cerveja']) ) { header('HTTP/1.1 400 Bad Request'); return 'Faltam parâmetros'; }
$validation = v::arr()->key('nome',$rule = v::alnum()->notEmpty()->noWhitespace()) ->key('estilo', $rule)
->validate($data['cerveja']); if ( !$validation ) { header('HTTP/1.1 400 Bad Request'); return 'Faltam parâmetros'; }
$cerveja = $mapper->cervejas(array( 'nome' => $nome ))->fetch(); if ( !$cerveja ) { header('HTTP/1.1 404 Not Found'); return 'Não encontrada'; }
$newNome = filter_var( $data['cerveja']['nome'], FILTER_SANITIZE_FULL_SPECIAL_CHARS ); $newEstilo = filter_var( $data['cerveja']['estilo'], FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$cerveja->nome = $newNome; $cerveja->estilo = $newEstilo; $mapper->cervejas->persist($cerveja); $mapper->flush();
header('HTTP/1.1 200 Ok'); return 'Cerveja atualizada';});
// removidas algumas verificações para ficar melhor no slide (http://github.com/ivanrosolen/RestBeer)
Tuesday, July 2, 13
Remover uma cerveja
Tuesday, July 2, 13
$router->delete('/cervejas/*', function ($nome) use ($mapper) {
$nome = filter_var( $nome, FILTER_SANITIZE_FULL_SPECIAL_CHARS );
if ( !isset($nome) || v::not(v::alnum()->notEmpty())->validate($nome) ) { header('HTTP/1.1 400 Bad Request'); return 'Faltam parâmetros'; }
$cerveja = $mapper->cervejas(array( 'nome' => $nome ))->fetch();
if ( !$cerveja ) { header('HTTP/1.1 404 Not Found'); return 'Não encontrada'; }
$mapper->cervejas->remove($cerveja); $mapper->flush(); header('HTTP/1.1 200 Ok'); return 'Cerveja removida';});
Tuesday, July 2, 13
Formatar Resultado
Tuesday, July 2, 13
$jsonRender = function ($data) {
header('Content-Type: application/json');
if ( v::string()->validate($data) ) { $data = array($data); }
return json_encode($data,true);};
$router->always('Accept', array('application/json' => $jsonRender));
Tuesday, July 2, 13
Autenticação básica
Tuesday, July 2, 13
// do not use this!function checkLogin($user, $pass) { return $user === 'admin' && $pass === 'admin';}
$router->get('/admin', function () {
return 'RestBeer Admin Protected!';
})->authBasic('Secret Area', function ($user, $pass) {
return checkLogin($user, $pass);
});
Tuesday, July 2, 13
REFERÊNCIAS
Tuesday, July 2, 13
Source
https://github.com/ivanrosolen/RestBeer
Tuesday, July 2, 13
https://github.com/Respect/
http://respect.li/ (docs inglês)
http://www.cssexperts.net/respect-rest-docs-br/ (docs e exemplos do rest pt-br)
http://www.slideshare.net/Alganet/rest-faa-o-servio-direito
Tuesday, July 2, 13
CONTATO
Tuesday, July 2, 13
@ivanrosolen
http://ivanrosolen.com
Tuesday, July 2, 13