O documento apresenta três frases principais sobre Jesus: 1) Jesus disse para virem a ele todos os cansados e oprimidos que ele daria descanso; 2) Mateus 11:28 é citado; 3) Aproximando-se da pureza do REST em Java através do HATEOAS e otimização do HTTP.
Approaching Pure REST in Java: HATEOAS and HTTP Tuning
1. Then Jesus said, "Come to me, all of you
who are weary and carry heavy burdens,
and I will give you REST."
Matthew 11:28
2. JavaO
ne LA
2012 TAM
Approaching Pure
REST in Java:
HATEOAS and HTTP Tuning
Eder Ignatowicz
Senior Architect, Dextra
3. Software Craftsman @ Dextra
(Arquitetura, NoSQL, Devops, QA)
Doutorando na Unicamp
(Polyglot Persistence em Cidades Digitais)
Professor na Faccamp e Unisal
Editor líder no InfoQ Brasil
@ederign
4. Galera Ponta Firme e que Manda bem
Dextra
Projetos Desafiadores
Qualidade de Vida
Ambiente de Melhoria Contínua
5. WE’R
E
Galera Ponta Firme e que Manda bem
Dextra
Projetos Desafiadores
HIRIN
Qualidade de Vida
G!!!
Ambiente de Melhoria Contínua
8. TEMPOS DIFÍCEIS...
MUITOS “PADRÕES”
RMI, Corba, DCOM
MUITOS FORNECEDORES
Sun, Microsoft, OASIS, OMG
MUITAS LÁGRIMAS
Não existia interoperabilidade
Reinvenção da roda
Vendor “lock-in”
13. REST
Roy Fielding Dissertation REpresentational State Transfer
ESTILO DE ARQUITETURA DE SOFTWARE PARA SISTEMAS
DISTRIBUÍDOS HYPERMEDIA SEMELHANTES A WORLD
WIDE WEB
14. PRINCÍPIOS E RESTRIÇÕES REST
CLIENTE-SERVIDOR
SERVIDOR STATELESS
CACHE
INTERFACE UNIFORME
IDENTIFICAÇÃO DE RECURSOS
MANIPULAÇÃO DESTES RECURSOS ATRAVÉS DE REPRESENTAÇÕES
MENSAGENS AUTO-DESCRITIVAS
HYPERMEDIA COMO ENGINE DO ESTADO DA APLICAÇÃO
ARQUITETURA EM CAMADAS
CÓDIGO SOB DEMANDA
(OPCIONAL)
16. GET Buscar recursos, cache
POST Criar um novo recurso
PUT Atualizar (todo o) recurso existente
DELETE Remover um recurso
PATCH Atualizar (parte de) um recurso
17. NÃO RESTful
VERBO URI (Substantivo) Ação
POST /bookmarks/create Criar
GET /bookmarks/show/1 Visualizar
POST /bookmarks/update/1 Alterar
GET/POST /bookmarks/delete/1 Apagar
RESTful
VERBO URI (Substantivo) Ação
POST /bookmarks/ Criar
GET /bookmarks/1 Visualizar
PUT /bookmarks/1 Alterar
DELETE /bookmarks/1 Apagar
18. TOLERÂNCIA A FALHAS
NOSSOS
SONHOS
NA INTE
SEGURANÇA SISTE GRAÇÃO
MAS DE
ESCALABILIDADE
BAIXO ACOPLAMENTO
20. “
“O que precisa ser feito para que entendam que
no estilo arquitetural REST o hypertext é um
pré-requisito?
Em outras palavras, se a engine do estado da
aplicação (e consequentemente sua API) não é
guiada por hypertext, então sua aplicação não
pode ser RESTful e nem ter uma API REST. PONTO.
Existe por ai algum manual que necessite ser
consertado?”
Roy Thomas Fielding
22. Richardson’s Maturity Model
REST Sagrado
Nível 3: Controles Hypermedia
Nível 2: Verbos HTTP
Nível1: Recursos
Nível 0: O pântano do POX
23. Nível 0: O pântano do POX
Uma URI, um método HTTP
XML-RPC / SOAP / POX
HTTP usado como transporte
POST /agendamentoService HTTP/1.1
[headers...]
<appointmentRequest>
<slot doctor = "rcmito" start = "1400" end = "1450"/>
<patient id = "ederi"/>
</appointmentRequest>
24. Nível 1: Recursos
Cada recurso tem uma única URI
URI tunneling
Um único verbo HTTP (POST ou GET)
HTTP usado como transporte
POST /slots/1234 HTTP/1.1
[headers...]
<appointmentRequest>
<patient id = "ederi" />
</appointmentRequest>
25. Level 2: HTTP Verbs
Muitas URIs, utilizando corretamente
os verbos HTTP
Uso correto dos códigos de resposta
Expõe estado e não comportamento
CRUD
GET /doctors/rcmito/slots?date=20121010?status=open
HTTP/1.1
[headers...]
HTTP/1.1 200 OK
<openSlotList>
<slot id = “1234” start=”1400” end=”1450” />
<slot id = “1234” start=”1600” end=”1650”/>
</openSlotList>
27. Nível 3: Controles Hypermedia
Hypermedia As The Engine of Application State
(HATEOAS)
Recursos auto descritivos
Clientes só precisam saber a URI root (home page) de
uma API e os media types utilizados
O resto é HTTP e links
28. “ O nome Representational State Transfer foi
escolhido com a intenção de criar uma imagem de
como uma aplicação Web bem desenvolvida se
comporta: uma rede de páginas web (máquina de
estados), onde o usuário navega selecionando
links (transições de estados), resultando na
próxima página (próximo estado da aplicação).
Roy Thomas Fielding
29. ESTADO ESTADO
http://uri
Transição
Transição
ESTADO
Transição
Transição
ESTADO ESTADO
30. HTTP/1.1 201 Created
Location: http://jogano10.com/slots/1234/appointment
[various headers]
<appointment>
<slot id = "1234" doctor = "rcmito" start = "1400"
end = "1450"/>
<patient id = "ederi"/>
<link rel = "/linkrels/appointment/cancel"
uri = "/slots/1234/appointment"/>
<link rel = "/linkrels/appointment/addTest"
uri = "/slots/1234/appointment/tests"/>
<link rel = "self"
uri = "/slots/1234/appointment"/>
<link rel = "/linkrels/appointment/updateContactInfo"
uri = "/patients/ederi/contactInfo"/>
</appointment>
39. Hypermedia
Suporte a HATEOAS
// Server API
Response res = Response.ok(order)
.link("http://.../orders/1/ship", "ship")
.build();
// Client API
Response order = client.target(…)
.request("application/xml").get();
if (order.getLink(“ship”) != null) {
Response shippedOrder = client
.target(order.getLink("ship"))
.request("application/xml").post(null);
}
43. Mas, eu preciso mais do
que a semântica
GET/POST/PUT
DELETE/PATCH "But my model is different!".
You are not a special or
unique snowflake.
- should I build another
protocol? - should I add a new
HTTP method?
- answer 1: tough shit. you're
wrong, it can be modeled with
the uniform interface, it's
sufficiently general.
44. Concorrência?
If you do two PUTs at once,
one wins. The solution
depends on what you need.
For a lot of applications, "last
update wins" is a fine strategy.
If not, Etags are the solution.
45. Transações... ?!?
I want to debit one guy's
account at the same time, and
only if, I can credit another
guy's account. I could do two
PUTs in a row, but that's
begging for inconsistencies to
creep into the system.
answer 1: YAGNI. Answer 2:
what you probably want is a
new resource to encapsulate
46.
47. Não existe a necessidade
de API nem de
versionamento de APIs!!!
- So Iʼll wrap up where we
started. Youʼll find that the closer
you move to REST, the less of a
distinct API youʼll have at all.
The “regular” application and its
API will become one.
- The rub, and itʼs a big rub, is
not a technical one but a social
one. Building on a API requires
trust of stability, and “traditional”
websites donʼt provide for
52. JAX-RS e Cache Control
@Path("/doutores")
public class DoutoresService {
@Path("/{id}")
@GET
@Produces("application/xml")
public Response getDoutores(@PathParam("id") int id) {
List<Doutor> doutores = //getDoutores
CacheControl cc = new CacheControl();
cc.setMaxAge(3000);
return Response.ok(doutores).cacheControl(cc).build();
}
}
53. JAX-RS e Gets Condicionais
Last-Modified: Mon, 29 Jun 2012 02:28:12 GMT
ETag: "3e86-410-3596fbbc"
O cache está valido?
304 “Not Modified”
Não está?
200 “OK” + recurso válido
54. @Path("/doutores")
public class DoutoresService {
@Path("/{id}")
@GET
@Produces("application/xml")
public Response getDoutores(@PathParam("id") int id,
@Context Request request) {
EntityTag tag = // get tag mais atualizada
ResponseBuilder builder = null;
builder = request.evaluatePreconditions(tag);
if (builder != null){
return builder.cacheControl(cc).build();
}
Object doutores = // getDoutores
return Response.ok(doutores).cacheControl(cc).build();
}
}
55. JAX-RS e Cache-Control
@Path("/doutores")
O mesmo princípio se aplica
public class DoutoresService {
@Path("/{id}")
@GET
para PUTs e POSTs
@Produces("application/xml")
public Response getDoutores(@PathParam("id") int id) {
condicionais
List<Doutor> doutores = //getDoutores
CacheControl cc = new CacheControl();
cc.setMaxAge(3000);
}
}
(updates concorrentes)
return Response.ok(doutores).cacheControl(cc).build();
56. JSR 339: JAX-RS 2.0
Public Review Ballot 24/11/2012
Adopt a JSR
57. Client API
@Before
public void setUp() throws Exception {
// start the server
server = Main.startServer();
// create the client
Client c = ClientFactory.newClient();
target = c.target(Main.BASE_URI);
}
@After
public void tearDown() throws Exception {
server.stop();
}
@Test
public void testExtratoSemHATEOAS() {
String responseMsg = target.path("cartao/1/saldo").request()
.get(String.class);
assertEquals(value, responseMsg);
}
58. Interceptors/Handlers
Pontos de extensão: Logging, Compression, Security, etc.
@Provider
class LoggingFilter
implements RequestFilter, ResponseFilter {
@Override
public FilterAction preFilter(FilterContext ctx)
throws IOException {
logRequest(ctx.getRequest());
return FilterAction.NEXT;
}
@Override
public FilterAction postFilter(FilterContext ctx)
throws IOException {
logResponse(ctx.getResponse());
return FilterAction.NEXT;
}
59. Async
Suporte na API Client
// Acesso URI
Target target = client.target("http://.../atm/balance")…
// Chamada async e callback
Future<?> handle = target.request().async().get(
new InvocationCallback<String>() {
public void complete(String balance) { … }
public void failed(InvocationException e) { … }
});