rest beer v2

40
Criando APIs usando o micro-framework Respect

Upload: ivan-rosolen

Post on 14-Apr-2017

883 views

Category:

Technology


0 download

TRANSCRIPT

Criando APIsusando o micro-framework

Respect

Ivan RosolenGraduado em Sistemas de InformaçãoPós-graduado em Gerência de Projetos

Desenvolvedor a 14+ anosAutor de vários PHPT (testes para o PHP)

Entusiasta de novas tecnologias

Head of Innovation @ Arizona

CTO @ Mokation

@ivanrosolen

API

Vantagens

- Troca de informações entre sistemas- Múltiplas interfaces (web, mobile, CLI)- Módulos/Componentes- HTTP Status Codes- Controle de Acesso

https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

REST BEER

API com informações de Ceveja!

GET - http://hostname/cerveja/

POST - http://hostname/cerveja/

cerveja[nome]

cerveja[estilo]

PUT - http://hostname/cerveja/NOME

cerveja[nome]

cerveja[estilo]

DELETE - http://hostname/cerveja/NOME

RESPECT

Micro-framework para PHP 5.3+ construido por Alexandre Gaigalas (alganet) e comunidade.

Como?

Composer

- Controle de dependências

curl -s http://getcomposer.org/installer | phpphp composer.phar install

https://getcomposer.org

{

"name": "RestBeer Jelastic Demo",

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

}

}

Respect/Config

- 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

https://github.com/Respect/Config

db_server = "127.0.0.1"

db_name = "restbeer"

db_user = "user"

db_pwd = "pwd"

dsn_mysql = "mysql:host=[db_server];dbname=[db_name]"

<?php

use Respect\Config\Container;

// Ler arquivo de configuração

$config = new Container('config.ini');

echo $config->dsn_mysql; // mysql:host=127.0.0.1;dbname=restbeer

Respect/Relational

- Quase zero de configuracão (convenção)- Fluent interface: $mapper->author[7]->fetch();

- Diferentes tipos de banco de dados

- Registros são tratados como Plain Data Object

https://github.com/Respect/Relational

<?php

use Respect\Relational\Mapper;

// criar instância PDO com o banco

$mapper = new Mapper(new PDO('seudsn'));

// buscar todos os autores

$authors = $mapper->author->fetchAll();

// criar objeto de um registro

$obj = new stdClass;

$obj->name = 'Ivan Rosolen';

// "gravar" informação no banco

$mapper->author->persist($obj);

$mapper->flush();

Respect/Validation

- Fluent/Chained interface: v::numeric()->positive()->between(1, 256)->validate($num)

- 100+ validadores testados

- Fácil extender ou criar novas regras (Concrete API)

- Php 7 ( Quase pronto )

https://github.com/Respect/Validation

use Respect\Validation\Validator as v;

// validar número simples

v::numeric()->validate(42); //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']);

// negação de qualquer regra

$v = v::not(v::int())->validate(10); // false

// operadores lógicos

v::allOf(v::numeric(), v::hexa(), v::min(1)); // numeric, hexadecimal e pelo menos 1

v::oneOf(v::nullValue(), v::numeric()); // null ou numeric

Respect/Router

- Thin and lightweight controller para aplicações RESTful e APIs

- “Don't try to change PHP, small learning curve.”- If/Before/After/Accept/Auth/Any/By …

https://github.com/Respect/Rest

<?php

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';

});

// Separando regras das rotas :D

$router->get('/api/uri/*/*', 'Namespace\Cool\Class');

$router->post('/api/uri/', 'Namespace\Cool\Class');

$router->put('/api/uri/', 'Namespace\Cool\Class');

$router->delete('/api/uri/*', 'Namespace\Cool\Class');

Projeto

<?php

require_once realpath(__DIR__ . '/vendor/autoload.php');

use Respect\Rest\Router;

use Respect\Config\Container;

use Respect\Validation\Validator as v;

use Respect\Relational\Mapper;

//Ler arquivo de configuração

$config = new Container('config.ini');

// Criar instância PDO com o SQLite usando as configs

$mapper = new Mapper(new PDO($config->dsn_sqlite));

// Criar instância do router

$router = new Router();

//Rota para qualquer tipo de request (any)

$router->any('/', function () {

return 'RestBeer!';

});

GET Cerveja

$router->get('/cerveja/*', function ($data = null) use ($mapper) {

if ( !isset($data) ) {

$cervejas = $mapper->cervejas->fetchAll();

header('HTTP/1.1 200 Ok');

return $cervejas;

}

$data = filter_var( $data, FILTER_SANITIZE_FULL_SPECIAL_CHARS ); if ( v::not(v::alnum()->notEmpty())->validate($data) ) { header('HTTP/1.1 400 Bad Request'); return 'Faltam parâmetros'; }

$cerveja = $mapper->cervejas(array( 'nome' => $data ))->fetch();

if ( !$cerveja ) {

header('HTTP/1.1 204 No Content');

return;

}

header('HTTP/1.1 200 Ok');

return $cerveja;

});

POST Cerveja

$router->post('/cerveja', function () use ($mapper) {

if ( !isset($_POST) || !isset($_POST['cerveja']) || v::not(v::arr())->validate($_POST['cerveja']) ) { header('HTTP/1.1 400 Bad Request'); return 'Faltam parâmetros'; }

$valid = v::arr()->key('nome', $rule = v::alnum()->noWhitespace())->key('estilo', $rule)->validate($_POST['cerveja']); if ( !$valid ) { 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 422 Unprocessable Entity'); return 'Erro ao inserir cerveja'; }

header('HTTP/1.1 201 Created'); return 'Cerveja criada';});

PUT Cerveja

$router->put('/cerveja/*', 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'; }

$nome = filter_var( $nome, FILTER_SANITIZE_FULL_SPECIAL_CHARS ); if ( 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 204 No Content'); return; }

$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';}); * removido parte do código para ficar melhor no slide

DELETE Cerveja

$router->delete('/cerveja/*', 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 422 Unprocessable Entity');

return 'Erro ao validar cerveja';

}

$mapper->cervejas->remove($cerveja);

$mapper->flush();

header('HTTP/1.1 200 Ok');

return 'Cerveja removida';

});

Formatar Resultado

<?php

$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));

Basic Auth

<?php

// 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);

});

Deploy

Jelastic

- Locaweb?- Git- Barato- 14 Dias Grátis

Aplicações PHP no Jelastic https://t.co/aHi3ZixLon

Referências / Links

Dúvidas?

OBRIGADO!

Avalie esta palestrajoind.in/15207

Visite phpsp.org.br