Descobrindo 


APIs REST
Guilherme Cavalcanti
github.com/guiocavalcanti
Por quê?
1º

Definição

Hermética
2º

apotonick/roar
kevinswiber/siren
jsonapi.org

Como?

Por quê?

intridea/grape
lostisland/sawyer
caelum/restfulie
3º

What the f* is

Representational State Transfer
“I am getting frustrated by the number of
people calling any HTTP-based interface a
REST API.”
–Roy Fielding
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?
Pagamento

Pedido
O Problema

•

Ciclo de pedido

•

Ciclo de pagamento

•

Independentes

•

Comunicação assíncrona
através de message queue

•

Maximiza throughput
Pagamento

Pedido
Message 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

Pedir

Sanduíche
preparado

Atualizar

Pagar

Pagamento
realizado

Pegar

Sanduíche
entregue
Caixa

Escolher
pedido

Sanduíche
Escolhido

Lançar 

pagamento

Pagamento
Lançado
Construir media type
( o que é media type? )
“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 […]”
–Roy T. Fielding
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
Sanduíche
Variante

Feito por terceiros

application/vnd.subway.sanduiche-­‐v1+json
Nome
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?
“[…] 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.”
–Roy T. Fielding
HTTP Methods
•

GET

•

POST

•

PUT

•

PATCH

•

DELETE

•

OPTIONS
“ Rails is not restful “
Kind of comment…
Implementar
Pedir

Sanduíche
preparado

Atualizar

Pagar

Pagamento
realizado

Pegar

Sanduíche
entregue
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: Resposta
HTTP/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: Resposta
HTTP/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: Erro
HTTP/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])
jsonapi.org

•

Media type de propósito geral

•

Links, Coleções, etc
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-behypertext-driven

•

http://github.com/apotonick/roar

•

http://github.com/intridea/grape

•

http://jsonapi.org

Descobrindo APIs REST