RESTful Web APIs

& the hypermedia constraint

Alex Moore-Niemi

What's the intent of this presentation?

To get you to build RESTful web APIs, and to use the hypermedia constraint as a tool for doing that.

How do you get someone to use something?

force

  1. inspire them to want to use it
  2. show them how to use it

Why build RESTful Web APIs?

Constraints restrict complexity.

Flexibility for growth.

Ubiquitous support.

REST has 4 constraints

  • identification of resources
  • manipulation of resources through representations
  • self-descriptive messages
  • hypermedia as the engine of application state

Is REST new?

*muttering* Just seems like hype to me!

No.

REST (Representational State Transfer) is merely an academic codification of the architectural constraints that describe the Web.

What is the Web?

HTTP, URLs, and HTML.

Pssst. What about Javascript?

It satisfies one of the optional constraints in REST: "Mobile Code On Demand".

But like, what IS the web???

The web is a distributed computing system.

What do all useful computational systems need to do?

Manipulate state.

State on the Web is of two types:

  1. Resource state
  2. Application state

How do we make state changes?

Representations!

(That's why it's called Representational State Transfer. :))

How do we represent state transitions on the web?

Working RESTfully means leveraging the Web as a core technology and organizing principle.

How do we generally approach writing programs?

We model what we think needs to happen.

We check for libraries that support our use case.

We re-model our first pass given existing libraries.

We write our program in the context of a dependency graph.

If we approach the "Web" as libraries we can use, what do we get out of the box?

Protocol semantics.

Domain semantics.

Application semantics.

What are protocol semantics anyway?

"the set of rules regarding how to fashion valid requests and responses using one or more message protocols"

Yeah, yeah yeah... I've seen POST, PUT, DELETE, etc...

HTTP alone has a lot more semantics than you might think.

HTTP/2 was published as RFC 7540 in May 2015.

Meh. Why not just overload POST with everything you need?

When you use POST with overloaded semantics, you're limiting yourself to thinking in function calls.

Your alternative is message passing. Does the Web offer that?

Yes.

One of the Fielding constraints of REST is "self-describing messages", because the web requires a message passing style for its distributed model.

What can message passing give us that function calling can't?

Formally, they're equivalent. But if you expose functions, you've exposed method signatures, which couple your client's implementation to yours directly.

Instead we want to think declaratively: send a message of the desired state change, don't ask for a specific function to handle it.

The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be. Think of the internet - to live, it (a) has to allow many different kinds of ideas and realizations that are beyond any single standard and (b) to allow varying degrees of safe interoperability between these ideas.
If you focus on just messaging - and realize that a good metasystem can late bind the various 2nd level architectures used in objects - then much of the language-, UI-, and OS based discussions on this thread are really quite moot.

Alan Kay (inventor of Smalltalk), on messaging

For instance, if you want to create something and format your POST request wrong, the server could inspect your malformed message and reply with a response explaining how to actually create the new resource you were addressing.

If you're POST'ing essentially to just an undefined function (RPC-style) the server can't do any better than say "this doesn't exist in my namespace. :c"

Our standard error response:

{
  key: "system_error"
  message: "An unexpected error has occurred. Please contact support if the problem persists."
}

Collection+JSON write template:

"template" : {
  "data" : [
     {"name" : "full-name", "prompt" : "Full Name"},
     {"name" : "email", "prompt" : "Email"},
     {"name" : "blog", "prompt" : "Blog"},
     {"name" : "avatar", "prompt" : "Avatar"}
   ]
}

Protocol semantics help define the control flow of our application, but they would be a pretty weak application on their own.

POSTCreate
GETRead
PUTUpdate
PATCH
DELETEDelete

If we need more than CRUD, we need our own application semantics. So protocol semantics at bottom, application semantics at top...

Between "the HTTP request necessary to trigger a state transition" and "the purpose of the state transition"...

How do we fill the gap?

HTML

Hyper Text Markup Language is the original hypermedia type.

Its protocol semantics are limited: PUT and DELETE from HTTP are not supported.

Its domain semantics are specifically about sharing a network of human readable documents, which is a very popular and very flexible domain.

If your application matches that domain 1:1, you're all set: HTML has you covered. (Consider Wikipedia.)

This is where we will start our API.

Hypermedia

"a way for the server to tell the client what HTTP requests the client might want to make in the future"

H-Factors are the categories of state transitions that hypermedia can help the client and server format as representations (messages).




Search

What kinds of state do we have on the web?

So how do we design a RESTful API? (In brief.)

  1. Semantic descriptors: list all info a client might have as input/output

  2. Link relations: Draw a state diagram

  3. Check against existing profiles: can you leverage any?

  4. Choose a media type

  5. Write your profile of your application semantics

    The more you found in 3 and 4, the less you need to do in 5.

  6. Code!!

  7. Publish the "billboard URL"

7 Step Design Procedure from RESTful Web APIs by Leonard Richardson, Mike Amundsen, Sam Ruby

ZipErrands API

Use case: As a Zipcar member, I want to find the nearest car available, so that I can use it to run an errand that will take under an hour.

Input: current location of user.

Output: cars (must have distance to, features, picture of), car keys (allows device to unlock car), reservation invoice (billed amount).

Semantic descriptors: current_location, distance_to, features, picture_of, car_keys, reservation_invoice

Link relations: search, car, prev/next, back, claim

Reconcile names:

Why reconcile names?

Search engines like Google have a vested interest in being able to parse content on the web semantically. Ever received an email that highlighted your upcoming flight?

That's the power of using Schema.org markup.

What do we need out of a media type?

A way for the client to figure out: what kind of requests can I make, how do I make them, and why would I want to make them?

worst case: Protocol Semantics

best case: Application Semantics

[
  {
    "account_billing_info_id": 5639575,
    "account_id": 123456789,
    "last_four": "1111",
    "credit_card_type": "vi",
    "account_holder_name": "Suzanne Job",
    "primary": true,
    "expiration_month": "02",
    "expiration_year": "2019",
    "address_line_one": "35 Thomson place,",
    "address_line_two": "Apt No-105",
    "mumciplaity": "boston",
    "region": "Massachusetts",
    "country": "US"
  }
]

The media type most devs are familiar with is JSON, but it is not a hypermedia format.

What could a hypermedia format give us out of the box that a vanilla data structure like JSON can't?

As a client, how do I interpret x?

As a client, how do I make a request to find x?

"queries" : [
  {
    "rel" : "search", "href" : "http://example.org/friends/search",
    "prompt" : "Search",
    "data" : [
          {"name" : "search", "value" : ""}
    ]
  }
],

As a client, how do I make a request to find ys related to x?

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!",
      "body": "The shortest article. Ever."
    },
    "relationships": {
      "author": {
        "data": {"id": 42, "type": "people"}
      }
    }
  }],
  "included": [
    {
      "type": "people",
      "id": 42,
      "attributes": {
        "name": "John"
      }
    }
  ]
}

HTTP/1.1 200 OK
Content-Type: application/atom+xml

When we give a uniform (standardized) interface to the client, we don't need as many clients.

Obligatory RentalCarReservation example.

"The purpose of an API is to separate the client from the implementation: the client should know nothing about the implementation other than information given in the API, and the implementation should not take properties of any particular client into account. APIs enable us to separately develop code for various purposes, then reuse it widely."

Sedgewick's Algorithms

tl;dr

  • The Web is a distributed computing system that relies on message passing.
  • Resources have unique, addressable identifiers.
  • To modify the state of a resource, you send representations. (Messages.)
  • These representations should be self-describing, so that the client never needs out-of-band information to make its next request.
  • Work from the state transitions, not from the resources underneath. Design from representations of state change, not from the object whose state will change. Work from the messages, not from the objects.

Leverage the work of your community, and be proud of contributing to that community.