Criando APIs usando o micro-framework Respect

8,212 views

Published on

Criando APIs usando o micro-framework Respect

  1. 1. Criando APIs usando o micro-framework Respect
  2. 2. Ivan Rosolen Graduado em sistemas de Informçã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
  3. 3. API
  4. 4. O que é?
  5. 5. "[] 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
  6. 6. Porque criar uma API?
  7. 7. Múltiplas interfaces (web, mobile, CLI)
  8. 8. Integração com outros serviços da sua empresa Venda de recursos e dados
  9. 9. EXEMPLO
  10. 10. RestBeer
  11. 11. 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
  12. 12. RESPECT
  13. 13. Micro-framework para PHP 5.3+ construido por Alexandre Gaigalas (alganet) e comunidade
  14. 14. Instalando
  15. 15. 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
  16. 16. /etc/hosts 127.0.0.1 restbeer.local
  17. 17. .htaccess RewriteEngine On # Redirect all requests not pointing at an actual file to index.php RewriteCond %{REQUEST_FILENAME} !-f RewriteRule . index.php [L]
  18. 18. 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" } }
  19. 19. Instalando dependências curl -s http://getcomposer.org/installer | php php composer.phar install
  20. 20. Respect/Config
  21. 21. ‣ 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 instancias de objeto ‣ Arquivo config.ini: db_name = "restbeer.db" dsn = "sqlite:[db_name]" ‣ Utilização: use RespectConfigContainer; /** * Ler arquivo de configuração */ $config = new Container('config.ini'); echo $config->dsn; // sqlite:restbeer.db ‣ http://github.com/Respect/Config
  22. 22. Respect/Relational
  23. 23. ‣ 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: RespectData (http://github.com/Respect/Data) ‣ Utilização: use RespectRelationalMapper; // 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
  24. 24. Respect/Validation
  25. 25. ‣ 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 RespectValidationValidator 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
  26. 26. Respect/Router
  27. 27. ‣ 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 RespectRestRouter; // 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
  28. 28. Começando o projeto
  29. 29. // autoload do composer require 'vendor/autoload.php'; use RespectRestRouter; use RespectConfigContainer; use RespectValidationValidator as v; use RespectRelationalMapper; use RespectDataCollectionsCollection; /** * 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!'; });
  30. 30. Buscar cervejas
  31. 31. $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; });
  32. 32. Cadastrar uma cerveja
  33. 33. $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'; });
  34. 34. Alterar uma cerveja
  35. 35. $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)
  36. 36. Remover uma cerveja
  37. 37. $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'; });
  38. 38. Formatar Resultado
  39. 39. $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));
  40. 40. Autenticação básica
  41. 41. // 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); });
  42. 42. REFERÊNCIAS
  43. 43. Source https://github.com/ivanrosolen/RestBeer
  44. 44. 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
  45. 45. CONTATO
  46. 46. @ivanrosolen http://ivanrosolen.com contato@ivanrosolen.com

×