Criando APIs usando o micro-framework Respect

ivanrosolen 9,822 views 46 slides Jul 02, 2013
Slide 1
Slide 1 of 46
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46

About This Presentation

No description available for this slideshow.


Slide Content

Criando APIs
usando o micro-framework
Respect
Tuesday, July 2, 13

Ivan Rosolen
Graduado em sistemas de Informação
Pós-graduado em Gerência de Projetos
Desenvolvedor a 10+ anos
Autor 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.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . 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 composer
require '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
[email protected]
Tuesday, July 2, 13