Download - REST API Design for JAX-RS And Jersey

Transcript
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