Skip to content

Instantly share code, notes, and snippets.

@bentranter
Created October 20, 2016 18:07
Show Gist options
  • Save bentranter/b76d835e7d5fb74efa0a22bba7b3c498 to your computer and use it in GitHub Desktop.
Save bentranter/b76d835e7d5fb74efa0a22bba7b3c498 to your computer and use it in GitHub Desktop.
Notes about REST API Design from StormPath's Latest Webinar

Stormpath Presentation

They focus on security and high availability. Free for devs.

  • Latency caching?

What're the things you can use to make your life easier?

HATEOAS - Hypermedia As The Engine Of Application State. The API and all info is self-contained in the data sent to and from the server - no out-of band info. Basically, you shuldn't need to go elseqhere or look up docs.

Fielding's Requirements:

  • no fixed names/hierarchies
  • dynamically typed
  • communication protocol independent (not just HTTP)
  • media type centric
  • zero out-of-band knowledge - you should be able to browse the entire API without needing look at any docs, resources should link to each other

Most companies violate the zero out of band knowledge requirement.

Resources

  • Nouns, not verbs!!!
  • Coarse grained, not fine-grained
  • Architectural-style for use-case scalability
  1. Collections Resource

Eg: /applications - make it a plural noun! Eg: /application/thing123 - this is an individual thing in your applications collection

How do we dfine behaviour?

Duh! The HTTP verbs! But: don't use HTTP verbs 1:1 with CRUD ops (PUT and POST don't quite fit in). PUT can create, POST can modify.

PUT should be able to create a resource if it doesn't yet exist at a canonical location, ie, you'd define the ID instead of letting the server do it in the case of POST. PUT is idempotent, so you need to send every field in a resource (UNLIKE PATCH). In TLS/1.3, GET MUST BE IDEMPOTENT since the server can retry. Idempotentcy is very important because of HTTP caching.

POST can create, but don't allow creation to the canonical namespace. Also, you extremely need to send back a 201 Created with the LOCATION HEADER SET TO THE URI OF THE NEW RESOURCE!!!!! This is super important, since following creation, that's the canonical URI for that resource. POST can also update a resource using partial data because IT IS NOT IDEMPOTENT!

Media Types

These are really just a format specification and a set of parsing rules, ie:

application/ion+json - it's in JSON, and follows the ion spec (for example), so follow the ion parsing rules.

HATEOAS in JSON: Ion

Intuitive codification of Roy Fielding's spec.

Resources:

Consider this JSON object:

{
	"meta": { ... }, // new field that exists in every request!!
	"firstname": "Bob",
	"brithdate": "1993-26-06",
}

Esentially is a JSON object with a meta object. Imagine some JSON like,

{
	"meta": { ... },
	"items": [],
}

The meta field will have information like items in the collection, max lenght, etc.

HREF

  • distributed hypermedia is paramount
  • every accesible resource has a canonical unique URL
  • these replace IDs (IDs exist but are opaque)
  • critical for linking

How do you do this in JSON? XML has the XLINK spec, but JSON has nothing, but we should add it in the meta field.

// GET /accounts/xyz123

{
	"meta": {
		"href": "https://api.domain.com/accounts/xyz123/groups",
		"rel": ["collection"],
	},
	"name": "Bob",
	"birthDate": "1993-26-06",
}

More HATEOAS stuff

You ever find yourself needing to read the docs to figure out how to POST to your favourite API? That's bad, since it requires out of band knowledge. HTML knows how so... why don't APIs?

Use Forms in the meta field!

{
	"meta": { "href": "https://foo.io/users", "rel": ["create-form"], "method": "POST"},
	"items": [
		{"name": "login", "required": true, "label": "Username or Email"},
		{"name": "password", "secret": true, "required": true, "label": "Password"},
	]
}

What about Schemas/JSON-Schema?

  • not needed => REST != RDBMS (schemas aren't necessary for browsers/HTML)
  • forms do the same thing and are more flexible/powerful

Last Thoughts

  • make it as easy as possible for a user to use/browse your API
  • the server should support multiple formats depending on the client, ie, send JSON for application/json, HTML for text/html, plaintext for text/plain.
  • versioning: do it the media-type from the beginning, or at the very least, make sure your URLs will work the same today as they will 2 years in the future. people like to save URLs in databases
  • resource extension: /applications/abc123.json - don't do it, there's an Accept header for a reason. Obviously this isn't horrible and works in some cases, but consider using Content Negotiation
  • just use camelCase
  • dates and times: lol. please use ISO 8601 and USE UTC time! (make your server generate UTC time).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment