REST API Design for JAX-RS And Jersey

79
REST + JSON APIs with JAX-RS Les Hazlewood CTO, Stormpath stormpath.com

description

Designing and building a really clean and intuitive ReST API is no small feat. You have to worry about resources, collections of resources, pagination, query parameters, references to other resources, which HTTP methods to use, HTTP caching, security, and more. And you have to make sure it lasts and doesn’t break clients as you add features over time. Furthermore, although there are many references on creating REST APIs with XML, there are far fewer references on REST + JSON. It is enough to drive you crazy. This session demonstrates how to design and implement an elegant REST API.

Transcript of REST API Design for JAX-RS And Jersey

Page 1: REST API Design for JAX-RS And Jersey

REST + JSON APIswith JAX-RS

Les HazlewoodCTO, Stormpathstormpath.com

Page 2: REST API Design for JAX-RS And Jersey

.com

• Identity Management andAccess Control API

• Security for your applications• User security workflows• Security best practices• Developer tools, SDKs, libraries

Page 3: REST API Design for JAX-RS And Jersey

Outline• REST Fundamentals• Design:

Base URLVersioningResource FormatReturn ValuesContent NegotiationReferences (Linking)PaginationQuery ParametersAssociations

ErrorsIDsMethod OverloadingResource ExpansionPartial ResponsesCaching & EtagsSecurityMulti TenancyMaintenance

• Coding Time! (JAX-RS-based App)

Page 4: REST API Design for JAX-RS And Jersey

Why REST?

• Scalability• Generality• Independence• Latency (Caching)• Security• Encapsulation

Learn more at Stormpath.com

Page 5: REST API Design for JAX-RS And Jersey

HATEOAS

• Hypermedia

• As

• The

• Engine

• Of

• Application

• State

Further restriction on REST architectures.Learn more at Stormpath.com

Page 6: REST API Design for JAX-RS And Jersey

REST Is Easy

Learn more at Stormpath.com

Page 7: REST API Design for JAX-RS And Jersey

REST Is *&@#$! Hard(for providers)

Learn more at Stormpath.com

Page 8: REST API Design for JAX-RS And Jersey

REST can be easy

(if you follow some guidelines)

Learn more at Stormpath.com

Page 9: REST API Design for JAX-RS And Jersey

Example Domain: Stormpath

• Applications• Directories• Accounts• Groups• Associations• Workflows

Page 10: REST API Design for JAX-RS And Jersey

Fundamentals

Learn more at Stormpath.com

Page 11: REST API Design for JAX-RS And Jersey

Resources

Nouns, not Verbs

Coarse Grained, not Fine Grained

Architectural style for use-case scalability

Learn more at Stormpath.com

Page 12: REST API Design for JAX-RS And Jersey

/getAccount

/createDirectory

/updateGroup

/verifyAccountEmailAddress

What If?

Learn more at Stormpath.com

Page 13: REST API Design for JAX-RS And Jersey

/getAccount/getAllAccounts/searchAccounts/createDirectory/createLdapDirectory/updateGroup/updateGroupName/findGroupsByDirectory/searchGroupsByName/verifyAccountEmailAddress/verifyAccountEmailAddressByToken…Smells like bad RPC. DON’T DO THIS.

What If?

Learn more at Stormpath.com

Page 14: REST API Design for JAX-RS And Jersey

Keep It Simple

Learn more at Stormpath.com

Page 15: REST API Design for JAX-RS And Jersey

The Answer

Fundamentally two types of resources:

Collection Resource

Instance Resource

Learn more at Stormpath.com

Page 16: REST API Design for JAX-RS And Jersey

Collection Resource

/applications

Learn more at Stormpath.com

Page 17: REST API Design for JAX-RS And Jersey

Instance Resource

/applications/a1b2c3

Learn more at Stormpath.com

Page 18: REST API Design for JAX-RS And Jersey

Behavior• GET• PUT• POST• DELETE• HEAD

Learn more at Stormpath.com

Page 19: REST API Design for JAX-RS And Jersey

Behavior

POST, GET, PUT, DELETE

≠ 1:1Create, Read, Update, Delete

Learn more at Stormpath.com

Page 20: REST API Design for JAX-RS And Jersey

Behavior

As you would expect:

GET = ReadDELETE = DeleteHEAD = Headers, no Body

Learn more at Stormpath.com

Page 21: REST API Design for JAX-RS And Jersey

Behavior

Not so obvious:

PUT and POST can both be used forCreate and Update

Learn more at Stormpath.com

Page 22: REST API Design for JAX-RS And Jersey

PUT for Create

Identifier is known by the client:

PUT /applications/clientSpecifiedId

{ …}

Learn more at Stormpath.com

Page 23: REST API Design for JAX-RS And Jersey

PUT for Update

Full Replacement

PUT /applications/existingId{ “name”: “Best App Ever”, “description”: “Awesomeness”}

Learn more at Stormpath.com

Page 24: REST API Design for JAX-RS And Jersey

PUT

Idempotent

Learn more at Stormpath.com

Page 25: REST API Design for JAX-RS And Jersey

POST as CreateOn a parent resource

POST /applications{ “name”: “Best App Ever”}

Response:

201 CreatedLocation: https://api.stormpath.com/applications/a1b2c3

Learn more at Stormpath.com

Page 26: REST API Design for JAX-RS And Jersey

POST as UpdateOn instance resource

POST /applications/a1b2c3

{ “name”: “Best App Ever. Srsly.”}

Response:

200 OK

Learn more at Stormpath.com

Page 27: REST API Design for JAX-RS And Jersey

POST

NOT Idempotent

Learn more at Stormpath.com

Page 28: REST API Design for JAX-RS And Jersey

Media Types

• Format Specification + Parsing Rules• Request: Accept header• Response: Content-Type header

• application/json• application/foo+json• application/foo+json;application• …

Learn more at Stormpath.com

Page 29: REST API Design for JAX-RS And Jersey

Design Time!

Learn more at Stormpath.com

Page 30: REST API Design for JAX-RS And Jersey

Base URL

Learn more at Stormpath.com

Page 31: REST API Design for JAX-RS And Jersey

http(s)://api.foo.com

vs

http://www.foo.com/dev/service/api/rest

Learn more at Stormpath.com

Page 32: REST API Design for JAX-RS And Jersey

http(s)://api.foo.com

Rest Clientvs

Browser

Learn more at Stormpath.com

Page 33: REST API Design for JAX-RS And Jersey

Versioning

Learn more at Stormpath.com

Page 34: REST API Design for JAX-RS And Jersey

URL https://api.stormpath.com/v1

vs.

Media-Type application/json+foo;application&v=1

Learn more at Stormpath.com

Page 35: REST API Design for JAX-RS And Jersey

Resource Format

Learn more at Stormpath.com

Page 36: REST API Design for JAX-RS And Jersey

Media Type

Content-Type: application/json

When time allows:

application/foo+jsonapplication/foo+json;bar=baz&v=1…

Learn more at Stormpath.com

Page 37: REST API Design for JAX-RS And Jersey

camelCase

‘JS’ in ‘JSON’ = JavaScript

myArray.forEach Not myArray.for_each

account.givenNameNot account.given_name

Underscores for property/function names are unconventional for JS. Stay consistent.

Learn more at Stormpath.com

Page 38: REST API Design for JAX-RS And Jersey

Date/Time/Timestamp

There’s already a standard. Use it: ISO 8601

Example:

{ …, “createdTimestamp”: “2012-07-10T18:02:24.343Z”}

Use UTC!

Learn more at Stormpath.com

Page 39: REST API Design for JAX-RS And Jersey

HREF

• Distributed Hypermedia is paramount!• Every accessible Resource has a unique URL.• Replaces IDs (IDs exist, but are opaque).

{ “href”: https://api.stormpath.com/v1/accounts/x7y8z9”, …}

Critical for linking, as we’ll soon see

Learn more at Stormpath.com

Page 40: REST API Design for JAX-RS And Jersey

Response Body

Learn more at Stormpath.com

Page 41: REST API Design for JAX-RS And Jersey

GET obvious

What about POST?

Return the representation in the response when feasible.

Add override (?_body=false) for control

Learn more at Stormpath.com

Page 42: REST API Design for JAX-RS And Jersey

Content Negotiation

Learn more at Stormpath.com

Page 43: REST API Design for JAX-RS And Jersey

Header

• Accept header

• Header values comma delimited in order of preference

GET /applications/a1b2c3Accept: application/json, text/plain

Learn more at Stormpath.com

Page 44: REST API Design for JAX-RS And Jersey

Resource Extension

/applications/a1b2c3.json/applications/a1b2c3.csv…

Conventionally overrides Accept header

Learn more at Stormpath.com

Page 45: REST API Design for JAX-RS And Jersey

Resource Referencesaka ‘Linking’

Learn more at Stormpath.com

Page 46: REST API Design for JAX-RS And Jersey

• Hypermedia is paramount. • Linking is fundamental to scalability.

• Tricky in JSON• XML has it (XLink), JSON doesn’t• How do we do it?

Learn more at Stormpath.com

Page 47: REST API Design for JAX-RS And Jersey

Instance Reference

GET /accounts/x7y8z9

200 OK{ “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, …, “directory”: ????}

Learn more at Stormpath.com

Page 48: REST API Design for JAX-RS And Jersey

Instance Reference

GET /accounts/x7y8z9

200 OK{ “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, …, “directory”: { “href”: “https://api.stormpath.com/v1/directories/g4h5i6” }}

Learn more at Stormpath.com

Page 49: REST API Design for JAX-RS And Jersey

Collection Reference

GET /accounts/x7y8z9

200 OK{ “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, …, “groups”: { “href”: “https://api.stormpath.com/v1/accounts/x7y8z9/groups” }}

Learn more at Stormpath.com

Page 50: REST API Design for JAX-RS And Jersey

Reference Expansion

(aka Entity Expansion, Link Expansion)

Learn more at Stormpath.com

Page 51: REST API Design for JAX-RS And Jersey

Account and its Directory?

Learn more at Stormpath.com

Page 52: REST API Design for JAX-RS And Jersey

GET /accounts/x7y8z9?expand=directory

200 OK{ “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, …, “directory”: { “href”: “https://api.stormpath.com/v1/directories/g4h5i6”, “name”: “Avengers”, “creationDate”: “2012-07-01T14:22:18.029Z”, … }}

Learn more at Stormpath.com

Page 53: REST API Design for JAX-RS And Jersey

Partial Representations

Learn more at Stormpath.com

Page 54: REST API Design for JAX-RS And Jersey

GET /accounts/x7y8z9?fields=givenName,surname,directory(name)

Learn more at Stormpath.com

Page 55: REST API Design for JAX-RS And Jersey

Pagination

Learn more at Stormpath.com

Page 56: REST API Design for JAX-RS And Jersey

Collection Resource supports query params:• Offset• Limit

…/applications?offset=50&limit=25

Learn more at Stormpath.com

Page 57: REST API Design for JAX-RS And Jersey

GET /accounts/x7y8z9/groups

200 OK{ “href”: “…/accounts/x7y8z9/groups”, “offset”: 0, “limit”: 25, “first”: { “href”: “…/accounts/x7y8z9/groups?offset=0” }, “previous”: null, “next”: { “href”: “…/accounts/x7y8z9/groups?offset=25” }, “last”: { “href”: “…”}, “items”: [ { “href”: “…” }, { “href”: “…” }, … ]}

Learn more at Stormpath.com

Page 58: REST API Design for JAX-RS And Jersey

Many To Many

Learn more at Stormpath.com

Page 59: REST API Design for JAX-RS And Jersey

Group to Account

• A group can have many accounts• An account can be in many groups• Each mapping is a resource:

GroupMembership

Learn more at Stormpath.com

Page 60: REST API Design for JAX-RS And Jersey

GET /groupMemberships/23lk3j2j3

200 OK{ “href”: “…/groupMemberships/23lk3j2j3”, “account”: { “href”: “…” }, “group”: { “href”: “…” }, …}

Learn more at Stormpath.com

Page 61: REST API Design for JAX-RS And Jersey

GET /accounts/x7y8z9

200 OK{ “href”: “…/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, …, “groups”: { “href”: “…/accounts/x7y8z9/groups” }, “groupMemberships”: { “href”: “…/groupMemberships?accountId=x7y8z9” }}

Learn more at Stormpath.com

Page 62: REST API Design for JAX-RS And Jersey

Errors

Learn more at Stormpath.com

Page 63: REST API Design for JAX-RS And Jersey

• As descriptive as possible• As much information as possible• Developers are your customers

Learn more at Stormpath.com

Page 64: REST API Design for JAX-RS And Jersey

POST /directories

409 Conflict{ “status”: 409, “code”: 40924, “property”: “name”, “message”: “A Directory named ‘Avengers’ already exists.”, “developerMessage”: “A directory named ‘Avengers’ already exists. If you have a stale local cache, please expire it now.”, “moreInfo”: “https://www.stormpath.com/docs/api/errors/40924”} Learn more at Stormpath.com

Page 65: REST API Design for JAX-RS And Jersey

Security

Learn more at Stormpath.com

Page 66: REST API Design for JAX-RS And Jersey

Avoid sessions when possibleAuthenticate every request if necessaryStateless

Authorize based on resource content, NOT URL!

Use Existing Protocol:Oauth 1.0a, Oauth2, Basic over SSL only

Custom Authentication Scheme:Only if you provide client code / SDKOnly if you really, really know what you’re doing

Use API Keys instead of Username/Passwords

Learn more at Stormpath.com

Page 67: REST API Design for JAX-RS And Jersey

HTTP Authentication Schemes

• Server response to issue challenge:

WWW-Authenticate: <scheme name> realm=“Application Name”

• Client request to submit credentials:

Authorization: <scheme name> <data>

Learn more at Stormpath.com

Page 68: REST API Design for JAX-RS And Jersey

401 vs 403

• 401 “Unauthorized” really means Unauthenticated

“You need valid credentials for me to respond to this request”

• 403 “Forbidden” really means Unauthorized

“I understood your credentials, but so sorry, you’re not allowed!”

Learn more at Stormpath.com

Page 69: REST API Design for JAX-RS And Jersey

API Keys

• Entropy• Password Reset• Independence• Speed• Limited Exposure• Traceability

Learn more at Stormpath.com

Page 70: REST API Design for JAX-RS And Jersey

IDs

Learn more at Stormpath.com

Page 71: REST API Design for JAX-RS And Jersey

• IDs should be opaque• Should be globally unique• Avoid sequential numbers

(contention, fusking)• Good candidates: UUIDs, ‘Url64’

Learn more at Stormpath.com

Page 72: REST API Design for JAX-RS And Jersey

HTTP Method Overrides

Learn more at Stormpath.com

Page 73: REST API Design for JAX-RS And Jersey

POST /accounts/x7y8z9?_method=DELETE

Learn more at Stormpath.com

Page 74: REST API Design for JAX-RS And Jersey

Caching & Concurrency Control

Learn more at Stormpath.com

Page 75: REST API Design for JAX-RS And Jersey

Server (initial response): ETag: "686897696a7c876b7e”

Client (later request):If-None-Match: "686897696a7c876b7e”

Server (later response):304 Not Modified

Learn more at Stormpath.com

Page 76: REST API Design for JAX-RS And Jersey

Maintenance

Learn more at Stormpath.com

Page 77: REST API Design for JAX-RS And Jersey

Use HTTP Redirects

Create abstraction layer / endpoints when migrating

Use well defined custom Media Types

Learn more at Stormpath.com

Page 78: REST API Design for JAX-RS And Jersey

IT’S CODING TIME!!!

• Let’s build a JAX-RS REST App!

• git clone https://github.com/stormpath/todos-jersey.git

Learn more at Stormpath.com

Page 79: REST API Design for JAX-RS And Jersey

.com

• Free for any application• Eliminate months of development• Automatic security best practices

Sign Up Now: Stormpath.com

Les Hazlewood | @lhazlewood