Descobrindo
APIs REST
Guilherme Cavalcantigithub.com/guiocavalcanti
Por quê?
1º
Definição Hermética
2º
Como? Por quê?
intridea/grape
apotonick/roar
lostisland/sawyer
jsonapi.org
kevinswiber/siren
caelum/restfulie
3º
What the f* isRepresentational State Transfer
–Roy Fielding
“I am getting frustrated by the number of people calling any HTTP-based interface a
REST API.”
Como?
• Problema conhecido por todos
• Passo a passo para projetar e implementar uma API REST
• Erros comuns, trade-offs e falácias
O que é rest e hypermedia?
• Estilo arquitetural
• Restrições
O que é REST/Hypermedia?
• Construção de sistemas distribuídos
• Em 99% dos casos sistemas que funcionam na Web
• Aplicativos mobile conversando com APIs
• Aplicativos Web convesando com Aplicativos Web
• Walledgarden
O processo
1. Entender o workflow que a API irá implementar
2. Construir máquina de estados
3. Construir media types
4. Implementar :)
Entender o workflow
Entender workflow
• Pensar em termos de processos de negócio
• Quantos e quais passos serão necessários?
PedidoPagamento
O Problema
• Ciclo de pedido
• Ciclo de pagamento
• Independentes
• Comunicação assíncrona através de message queue
• Maximiza throughput
PedidoPagamentoMessage Queue
Simplificado
• Na verdade são 3 ciclos independentes
• Mais lucros
• Dica: Starbucks Does Not Use Two-Phase Commit
Criar máquina de estados
Criar máquina de estados: cliente
Sanduíche preparado
Pagamento realizado
Sanduíche entregue
Pedir Pagar Pegar
Atualizar
Caixa
Sanduíche Escolhido
Pagamento Lançado
Escolher pedido
Lançar pagamento
Construir media type
( o que é media type? )
–Roy T. Fielding
“To some extent, people get REST wrong because I failed to include enough detail on media type design within my dissertation.
That’s because I ran out of time […]”
Media types
• É o que o cliente precisa saber para entender:
• Comportamento (ou seja, quais transições saem de ume estado)
• Semântica de alguns atributos da representação
Exemplo: text/html
• Ao clicar no <a>: Requisição GET para href
• Ao submeter um <form>: Requisição method para action
Exemplo: text/html
• O browser só precisa entender o media type.
• Tanto faz se você está vendo o extrato da sua conta do banco ou um verbete na Wikipedia
• media type = comportamento + semântica
Exemplo: APIs
• Erros de validação
• Internacionalização de mensagens
• URLs
Media types
• É por isso que sempre dizem que APIs REST não precisam de Documentação
• Você só precisa descrever os media types utilizados
• A semântica dos métodos HTTP já é bem definida
• Utilizado nos cabeçalhos Accept e Content-‐type
Voltando: Construir media type
Voltando: Construir media type
application/vnd.subway.sanduiche-‐v1+json
Feito por terceiros
Nome
Variante
Sanduíche
Sanduíche: Semântica• id
• created_at
• pao
• queijo
• status
• updated_at
Pagamento: Semântica
• id
• created_at
• numero_cartao
• expira_em
• valor
Semântica
• Atributos que tem o mesmo significado para todos os recursos da API
• Comportamentos inesperados (erros de validação)
Comportamento: Relacionamentos
{ "links": [ { "rel": "self", "href": "/pedidos/1" }, { "rel": "pagamento", "href": "/pagamentos/pedidos/1" } ] }
Comportamento: Relacionamentos
• Representam as transições da nossa máquina de estados
• Aumentam o desacoplamento
• O cliente não precisa saber URLs a priori
Mas… Quais métodos utilizar?
–Roy T. Fielding
“[…] methods are not given meaning by the media type. Instead, the media type tells the client either
what method to use (e.g., anchor implies GET) or how to determine the method to use (e.g., form element says to look in method attribute). The client should already know what the methods mean (they are
universal) and how to dereference a URI.”
HTTP Methods• GET
• POST
• PUT
• PATCH
• DELETE
• OPTIONS
“ Rails is not restful “ Kind of comment…
Implementar
Sanduíche preparado
Pagamento realizado
Sanduíche entregue
Pedir Pagar Pegar
Atualizar
Fazer pedido: Requisição
POST /pedidos HTTP/1.1 Accept: application/vnd.subway.sanduiche-‐v1+json { "pao": "3queijos", "queijo": "suíço", "recheio": "club" }
Fazer pedido: RespostaHTTP/1.1 201 Created Content-‐type: application/vnd.subway.sanduiche-‐v1+json { "id": "1", "created_at": "2013-‐10-‐23T05:02Z", "updated_at": null, "pao": "3 queijos", "queijo": "suíço", "recheio": "club", "status": “em preparo", "links": [ { "rel": "self", "href": "/pedidos/1" }, { "rel": "pagamento", "href": "/pagamentos/pedidos/1" } ] }
Atualizar pedido: Requisição
PATCH /pedidos/1 HTTP/1.1 Accept: application/vnd.subway.sanduiche-‐v1+json { "queijo": "cheddar" }
Atualizar pedido: RespostaHTTP/1.1 200 Ok Content-‐type: application/vnd.subway.sanduiche-‐v1+json { "id": "1", "created_at": "2013-‐10-‐23T05:02Z", "updated_at": null, "pao": "3 queijos", "queijo": "cheddar", "recheio": "club", "links": [ { "rel": "self", "href": "/pedidos/1" }, { "rel": "pagamento", "href": "/pagamentos/pedidos/1" } ] }
Atualizar pedido: ErroHTTP/1.1 409 Conflict Content-‐type: application/vnd.subway.sanduiche-‐v1+json { "id": "1", "created_at": "2013-‐10-‐23T05:02Z", "updated_at": null, "pao": "3 queijos", "queijo": "suiço", "recheio": "club", "links": [ { "rel": "self", "href": "/pedidos/1" }, { "rel": "pagamento", "href": "/pagamentos/pedidos/1" } ] }
Como saber se é possível mudar o pedido?
OPTIONS /pedidos/1 HTTP/1.1
HTTP/1.1 200 Ok Allow: GET, PATCH
Pagar pedido: REQUISIÇÃO
• Lembra do media type?
• Utilizar relacionamentos
Pagar pedido: REQUISIÇÃO
GET /pagamentos/pedidos/1 HTTP/1.1 Accept: application/vnd.subway.sanduiches-‐v1+json { "numero_cartao": "123312", "expira_em": "12/12", "valor": "12.45" }
Ponto de vista do caixa: fila de sanduíches
GET /pedidos HTTP/1.1 Accept: application/vnd.subway.sanduiches-‐v1+json{ "total": 12, "page": 1, "per_page": 10, "items": [ { "id": “1”, “status”: "pago" … }, { "id": “2”, “status”, “em preparo" … } ] }
Listar pedido: media type
• É necessário criar seu próprio media type?
• Não! Já existem vários:
• collection+json
• atom+xml
Gems
roar
beer = Beer.new(:title => "Lonestar Beer") beer.post(order.links[:items])
Obrigado :)
Referências• http://www.infoq.com/articles/webber-rest-workflow
• http://www.enterpriseintegrationpatterns.com/ramblings/18_starbucks.html
• http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
• http://github.com/apotonick/roar
• http://github.com/intridea/grape
• http://jsonapi.org