Criando APIs usando o micro-framework Respect

Post on 05-Dec-2014

4.165 views 13 download

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": "ivan@rosolen.net" } ], "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

CONTATO

Tuesday, July 2, 13

@ivanrosolen

http://ivanrosolen.com

contato@ivanrosolen.com

Tuesday, July 2, 13