javaone 2009 - ts-5276 - restful protocol buffers

38
RESTful Protocol Buffers Matt O’Keefe/Alex Antonov Sears Holdings/Orbitz Worldwide

Upload: matt-okeefe

Post on 12-Nov-2014

13.529 views

Category:

Technology


0 download

DESCRIPTION

Abstract:Jini has served Orbitz well, but at the cost of tight coupling due in part to shared code and Java™ platform serialization rules. To improve agility, Orbitz is migrating to a RESTful Web services architecture using protocol buffers to define message formats. The result is loosely coupled services with autonomous lifecycles supporting evolvability and innovative mashup-style development.This session is intended for experienced architects and tech leads who are familiar with distributed systems and data encoding methods.It covers• Using document schemas to constitute language-neutral contracts• Using standard HTTP plumbing and intermediaries• Implementing a reverse proxy for request routing based on RESTful URLs• Applying OLAs for governance and service isolation• Writing automated service layer tests to ensure backward compatibility

TRANSCRIPT

Page 1: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

RESTfulProtocol Buffers

Matt O’Keefe/Alex AntonovSears Holdings/Orbitz Worldwide

Page 2: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

22

Agenda

> Problem Statement> Why REST?> Why Protocol Buffers?> Implementation Details

Plumbing Data Modeling

> Testing and Release Management> Results

Page 3: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

33

A Little History – JavaOne 2004

> “Miss Con-Jini-ality”Dukie award winner

> SOA before SOAwas a buzzword

> Dynamic ServiceRegistration andDiscovery

> Inexpensive EJBAlternative

Page 4: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

44

Problem Statement> Management of Shared, Versioned Dependencies

with Serializable Objects is Difficult

Page 5: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

55

Architectural PrinciplesOur Decision-making Framework

> Loosely Coupled, Contractually Obligated Systems should have few dependencies with

freedom to evolve independently, but where dependencies and contracts do exist, they must be rigidly enforced.

> Release Early, Release Often Software should be released when ready, and of

high quality. It should be released in small iterations, and frequently, to keep the scope of change to a minimum.

Page 6: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

66

Agenda

> Problem Statement> Why REST?> Why Protocol Buffers?> Implementation Details

Plumbing Data Modeling

> Testing and Release Management> Results

Page 7: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

77

Why REST?Uniform Interface

http://rest.blueoxen.net/cgi-bin/wiki.pl?HttpMethods

Method Safe Idempotent VisibleSemantics

IdentifiableResource

Cacheable

GET X X X X X

HEAD X X X X X

PUT X X X

POST

DELETE X X X

OPTIONS X X X

http://rest.blueoxen.net/cgi-bin/wiki.pl?HttpMethods

Method Safe Idempotent VisibleSemantics

IdentifiableResource

Cacheable

GET X X X X X

HEAD X X X X X

PUT X X X

POST

DELETE X X X

OPTIONS X X X

Page 8: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

88

Why REST?Simplicity of HTTP

ClientOriginServer

GET /employees/current HTTP/1.1

HTTP/1.1 200 Ok

Page 9: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

99

Why REST?HTTP Intermediaries

UserAgent

EmployeeService

EmployeeServiceH/W

LoadBalancer

CustomerService

CustomerService

S/WGateway

S/WGateway

/employees/*

/customers/*

ProxyCache

UserAgent

EmployeeService

EmployeeServiceH/W

LoadBalancer

CustomerService

CustomerService

S/WGateway

S/WGateway

/employees/*

/customers/*

ProxyCache

Page 10: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

1010

Agenda

> Problem Statement> Why REST?> Why Protocol Buffers?> Implementation Details

Plumbing Data Modeling

> Testing and Release Management> Results

Page 11: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

1111

Why Protocol Buffers?Simple Message Formatmessage Person {

required string name = 1; required int32 id = 2; optional string email = 3;

enum PhoneType {

MOBILE = 0;

HOME = 1;

WORK = 2;

}

message PhoneNumber {

required string number = 1;

optional PhoneType type = 2 [default = HOME];

}

repeated PhoneNumber phone = 4;

} // Example from http://code.google.com/apis/protocolbuffers/docs/overview.html

Page 12: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

1212

Why Protocol Buffers?

> Performance Binary encoding 7-10x faster than JSON Even faster than Jini/JERI

> Maturity In use at Google for years Complete toolkit with good docs and community Support for multiple languages

> Evolvability Forward and Backward compatibility Passing of unknown data fields

Page 13: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

Why Protocol Buffers?Evolvability for Agile Oriented Architecture

A

C

B

message Person {

required string name = 1;required int32 id = 2;optional string email = 3;repeated PhoneNumber phone = 4;

}

message Person {

required string name = 1;required int32 id = 2;optional string email = 3;repeated PhoneNumber phone = 4;optional string username = 5;

}

Page 14: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

1414

Agenda

> Problem Statement> Why REST?> Why Protocol Buffers?> Implementation Details

Plumbing Data Modeling

> Testing and Release Management> Results

Page 15: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

1515

PlumbingWhat – Where – How

> RESTful Web Services> URLs> Standard Methods> Representations

Page 16: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

1616

RESTful Web ServicesBest Practices

> Use Nouns instead of Verbs> Use proper HTTP methods to indicate your

intentions> REST – No State> GET is the only immutable operation> Use HTTP Status codes to communicate the

status of your request> Use ‘_’ to separate the words in your URL

Using camelCasing leads to confusion

Page 17: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

1717

URLs

> Absolute Path should represent a group of data reducing segments that narrow down data selection GET /employees

returns entire set of employees GET /employees/current

returns only the ‘current’ subset of employees

Page 18: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

1818

URLs continued…

GET /employees/{id} returns a specific employee based on its ID

PUT /employees/{id} updates a specific employee

> Query String should be used for providing optional filtering parameters GET /employees/current?last_name=Johnson

returns a subset of current employees who’s last name is ‘Johnson’

Page 19: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

1919

Building a Server// EmployeeController.java@Controllerpublic class EmployeeController {

@Resourceprivate EmployeeService employeeService;

@RequestMapping(value = "/employees", method = RequestMethod.GET) public Employee getEmployeeById(@RequestParam(value="id")int id) {

return employeeService.findById(id); }}

<!– urlrewrite.xml --><urlrewrite> <rule> <from>/employees/([0-9]{1,})?</from> <to last="true">/employees?id=$1</to> </rule></urlrewrite>

Page 20: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

2020

Building a Client

// EmployeeServiceClient .javapublic interface EmployeeServiceClient {

@ServiceName(value=”getEmployeeById") public Employee getEmployeeById(@ParamName("id") int employeeId);}

// employee.protopackage employee;message Employee { required int32 id = 1; optional string name = 2; repeated Role role = 3; enum Role { DEVELOPER = 1; MANAGER = 2; }}

// EmployeeServiceClient .javapublic interface EmployeeServiceClient {

@ServiceName(value=”getEmployeeById") public Employee getEmployeeById(@ParamName("id") int employeeId);}

// employee.protopackage employee;message Employee { required int32 id = 1; optional string name = 2; repeated Role role = 3; enum Role { DEVELOPER = 1; MANAGER = 2; }}

Page 21: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

2121

Representations Content Encoding

> PROTO should be the default representation for all resources

> Use ‘Accept’ header to indicate alternative encodings application/json - the server will return a JSON

(and set the Content-Type to application/json) application/xml- the server will return an XML (and

set the Content-Type to application/xml) application/x-protobuf – the server will return the

protocol buffers binary (and set the Content-Type to application/x-protobuf)

Page 22: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

2222

Representations Content Encoding continued…

> When a Protocol Buffer is returned, the HTTP response should also include anX-Protobuf-Schema header containing the URI for the .proto schema file

> To support random requests using variable output format, i.e. JSON vs. PROTO vs. XML, use format parameter on the URL format parameter on the URL query Accept header PROTO format should be used by default if no

format guidance is provided

Page 23: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

2323

Agenda

> Problem Statement> Why REST?> Why Protocol Buffers?> Implementation Details

Plumbing Data Modeling

> Testing and Release Management> Results

Page 24: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

2424

Data ModelingObjects vs. Structures

> In distributed services one wants to separate data from behavior Each application has its own object model Contract between applications is defined only by

data structure Most business logic should reside in object models

which internally operate on the data received as a result of a distributed service call

Page 25: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

2525

Data ModelingObjects vs. Structures continued…

> Protocol Buffers .proto files provide language-agnostic structure

definition Over-the-wire binary data encoding

Decreases payload size Ability to deal with mismatching structure definitions Ability to convert into alternative formats (xml, json)

> Objects Provide behavior Should not be serializable

Page 26: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

26

Data ModelingObjects vs. Structures continued…

// Writing a messageEmployee.Builder builder = Employee.newBuilder();builder.setId(1).setName(“John”).setRole(Employee.Role.DEVELOPER);Employee employee = builder.build();employee.writeTo(response.getOutputStream());

// Reading a messageEmployee employee = Employee.parseFrom(request.getInputStream());

// Merging a messagebuilder.mergeFrom(request.getInputStream());Employee employee = builder.setId(2).build();

Page 27: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

2727

Data ModelingDomain Model

> Java Object Models Should provide behavioral logic Should encapsulate the data

Wrap the Proto Message with Java Object Model providing the behavior which uses data from the Proto

> “Services should be very thin, most logic should reside in objects” -- Martin Fowler Services should only coordinate interactions

between objects

Page 28: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

2828

Agenda

> Problem Statement> Why REST?> Why Protocol Buffers?> Implementation Details

Plumbing Data Modeling

> Testing and Release Management> Results

Page 29: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

2929

TestingWhy Service-Layer Testing is Important

> In order to safely release components independently, Certification Criteria must be defined

> Forward and backward compatibility must be tested and verified

> Test automation is key due to the increased number of releases

> Testing is easier with RESTful services Existing webapp testing tools can be leveraged Browsers can be used for manual tests

Page 30: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

3030

Release ManagementNo More Monolithic Builds

> Focus shifted to higher-order dependencies> Sequencing is important, but not simultaneity

Page 31: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

3131

ResultsSmaller, More Frequent Releases

> Loosely coupled components, released independently

> Greater agility and speed with smaller iterations> Less risk; no more monolithic build> Stronger contracts and better test coverage> Greater adoption of commonly used standards

and infrastructure

Page 32: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

3232

References

> REST – Roy Fielding’s Dissertation - http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

> RESTwiki - http://rest.blueoxen.net/cgi-bin/wiki.pl> Google Protocol Buffers -

http://code.google.com/apis/protocolbuffers/docs/overview.html

> Spring MVC - http://static.springframework.org/spring/docs/2.5.x/reference/mvc.html

> UrlRewrite Filter - http://tuckey.org/urlrewrite/

Page 33: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

3333

Matt O’Keefe/Alex [email protected]@orbitz.com

Matt O’Keefe/Alex [email protected]@orbitz.com

Page 34: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

3434

Appendix - Building a Server

> @Controller annotation is being used to indicate to Spring that this object class represents a controller

> @Resource annotation is being used to indicate to Spring that the annotated field should be injected with a bean corresponding to the type and/or name from the Spring Container

Page 35: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

3535

Appendix - Building a Server continued…

> @RequestMapping annotation is being used to indicate to Spring that the annotated method responds to a request pattern

> @RequestParam annotation can be used to indicate to Spring what URL parameter name the annotated argument should be mapped to with an optional required attribute to indicate if the parameter is required to be present in the URL (true by default).

Page 36: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

36

Appendix - Building a Client

> InvocationHandler logic would contain the following things: Read the Annotations and construct HTTP request

based on them Convert method arguments into URL parameters or

RESTful URL patterns Encode the data passed as arguments into format

acceptable by HTTP standards Provide abstraction for different possible communication

protocols such as JMS, HTTP, RMI, etc.

Page 37: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

37

Appendix - Building a Client continued…> @ServiceName annotation is being used to provide

instructions to the InvocationHandler on the following things:> The name of the service which is indicated by the

value attribute of the annotation> The argument-based url pattern (if one exists)> The content type of the desired result output which

is indicated by an optional contentType attribute of the annotation (default is protobuf)> Possible values: xml, json, text, protobuf

Page 38: JavaOne 2009 - TS-5276 - RESTful  Protocol Buffers

38

Appendix - Building a Client continued…> @ParamName annotation is being used to provide

instructions to the InvocationHandler on the following things:> The name of the parameter, as it is being identified

in the pattern of the service call in @ServiceName annotation

> The required status of the argument which is indicated by an optional required attribute of the annotation (default is false)

> If the name of the parameter is NOT part of the pattern defined in @ServiceName, it is being appended to the URL as part of the query string.