REST Workshop

1 HTTP RPC

1.1 Objective

Create a classic "RPC over HTTP" application for creating ads with pictures.

The application will encode the result of each operation in the body of the request.

For now, you only need to implement the server side. Use curl for testing the responses from the server.

1.2 Steps

1.2.1 Create the ad endpoint: http://localhost:3000/create-ad

This is where clients should POST a json object to create a new ad. The JSON that's sent to the server should look like this:

{
  "title": "Nice house for sale!",
  "body": "Four rooms, huge bath."
}

To test the endpoint you can use the example ad.json file like this:

curl --data-binary @../ad.json http://localhost:3000/create-ad

The server should return a document like this:

{
  "result": "ok",
  "data": {
    "id": "4fc494d10b6a9fcb09000001", 
    "body": "Four rooms, huge bath.", 
    "pictures": [], 
    "title": "Nice house for sale!"
  },
}

The id field inside the data object is used later on when generating URLs.

Similar for any unknown error, result should be error:

{
  "result": "error"
}

1.2.2 View ad endpoint: http://localhost:3000/ad?id=...

Clients can GET this with an "id" query parameter. The server will respond with something like this:

{
  "result": "ok",
  "data": {
    "title": "Nice house for sale!",
    "body": "Four rooms, huge bath."
  }
}

If the ad does not exist, result should be notFound:

{
  "result": "notFound"
}

1.2.3 Add picture endpoint: http://localhost:3000/add-picture?id=...

There are some example pictures available under ../../pictures.

See the node cheat sheet on how to add pictures to a Mongo object.

1.3 Example ad.json

{
  "title": "Nice house for sale!",
  "body": "Four rooms, huge bath."
}

2 Basic HTTP

2.1 Objective

The background and requirements are similar to the "RPC over HTTP" application, but now it's time to become a better and more "correct" HTTP component.

We will improve the application by moving generic application semantics one level down to the HTTP layer. We'll do this with proper use of status codes and headers.

We're expanding on the previous server, but this time we're also adding a client.

2.1.1 Common Requirements for Resources

The application shall follow these general requirements:

2.1.2 Content Types

Use application/json for all normal messages, and text/plain for error messages.

2.2 Steps

2.2.1 Create the 'create ad endpoint': http://localhost:3000/create-ad

This is where clients should POST a json object to create a new ad. The JSON that's sent to the server should look like this:

{
  "title": "Nice house for sale!",
  "body": "Four rooms, huge bath."
}

The server should return 200 Ok and a document like this:

{
  "type": "ad",
  "id": "4fc494d10b6a9fcb09000001", 
  "body": "Four rooms, huge bath.", 
  "pictures": [], 
  "title": "Nice house for sale!"
}

Try to send an invalid object (for example an empty document like /dev/null on unix or nul on windows) and make sure you're getting a proper 500 error code back.

2.2.2 View ad endpoint: http://localhost:3000/ad?id=...

Clients can GET this with an "id" query parameter. The server will respond with something like this:

{
  "type": "ad",
  "id": "4fc494d10b6a9fcb09000001", 
  "body": "Four rooms, huge bath.", 
  "pictures": [], 
  "title": "Nice house for sale!"
}

Try to fetch an ad that doesn't exist and make sure you're getting a 404 error.

2.2.3 Add picture endpoint: http://localhost:3000/add-picture

There are some example pictures available under ../../pictures.

See the node cheat sheet on how to add pictures to a Mongo object.

2.2.4 Create a client for creating ads

The client shall first create the ad and then attach all the pictures to the ad.

Suggested command line API:

$ ./add-ad.js "Nice house for sale" "Four rooms, huge bath." car.jpg dinosaur.jpg

The client must assert the status codes and content types returned. Proper error handling is not important now so just throw an exception on any failure.

2.3 Bonus Tasks

2.3.1 Proper error handling in the client

If the server returns an unexpected result or unprocessable content, do not crash but rather try to show the error message to the user. If the server returns text/plain, the user can be shown the text directly.

2.3.2 Add a Last-Modified header to the responses

2.3.3 Client to view an ad

Create a client that displays an ad.

Suggested command line API:

$ ./view-ad.js <id>
Fetching ad ...
Last-Modified: <time>
Title: <title>
Body: <body>

2.3.4 Caching Client

Improve the client and store the ad as ad-<id>.js. If executed twice it should do a conditional GET.

2.4 Example ad.json

{
  "title": "Nice house for sale!",
  "body": "Four rooms, huge bath."
}

3 Media Types

3.1 Objective

In this exercise it's time to move from application/json to use Ads'r'us' own media type. We will also remove all URL generation from the clients. The server will decide which interactions that are allowed.

3.2 Steps

Implement the API described in Ads'r'us API. Continue with the implementation you completed in the previous exercise.

Replace the usage of application/json with application/vnd.ad+json and application/vnd.ad-list+json. Update the add-ad.js client to start from the "ad list" URL and find the add-ad URL from the list document. In the end, the client should not hard code or generate any URLs.

3.3 Bonus

Work with another person/group and try your client against the other groups server. Add extra fields and headers to the responses to try to get the other client to fail. Make sure that you stay within the specification when adding fields and headers. It is also possible to change the URL that's served to the client.

3.4 Example ad.json

woot

4 Generic Media Types

4.1 Objective

Now we're moving from a highly specific media type to encode the same objects by using an existing media type.

4.2 Steps

Update the server and client to use the new variant of the API.

This document is an example on how one can document an API by using the REST principles. This version of the API use a domain specific media type with JSON serialization.

5 Ads'r'us API

This document describes an architecture for how agents should interact with Ads'r'us. Interactions with Ads'r'us follow the general architecture and constraints described in the REST dissertation and add some domain specific constraints.

We only implement a HTTP interface to our resources which come with its own set of constraints. As the world progresses, new specifications, updates and enhancements arrive and we try to stay as much as possible in line. However, we will always remain backwards compatible with our own published specifications.

Make sure to check back regularly to get the latest version of this specification!

5.1 General Architecture Rules

These are general rules and principles used. They apply as long as a specific interaction/resource does not specify something else.

All resources should return an Allow header if the method is not allowed/supported.

It is expected that the domain and objects that the resources describe evolve over time and thus the media types will need evolve over time too. Clients must silently ignore unknown fieds and should not expect optional fields to be present.

5.1.1 On Creating New Resources

When a new resource is created, the server MUST return the status code 201 and a Location header pointing to the newly created resource.

Many resources will include URIs to other resources and operations available for the client. The resources will include all links, even if the client may not be authorized to use them.

5.2 Expected usage

It is assumed that clients are pre-programmed with a link to an ad list when starting to interact with us.

5.3 Media Type: Single Ad / application/vnd.ad+json

{
  "title": "Nice house for sale!",
  "body": "Four rooms, huge bath.",
  "pictures": [
    URI, ...
  ]
  "self": URI,
  "add-picture": URI,
  "publish": URI,
  ...
}

Fields:

5.3.1 Updating Ads

When updating the ad, only these fields needs to be sent:

There is no described way to update only a subset of the fields in an ad.

5.4 Media Type: Ad List / application/vnd.ad-list+json

{
  "count": 10,
  "add-ad": URI,
  "ads": [
    {
      // See specification for application/vnd.ad+json
    }
  ],
  "next-page": URI,
  "prev-page": URI,
  ...
}

To insert a new ad into the list, send the data to the add-ad URI.

This document is an example on how one can document an API by using the REST principles. This version of the API uses the generic application/vnd.collection+json format instead of a specific media type.

6 Ads'r'us API

This document describes an architecture for how agents should interact with Ads'r'us. Interactions with Ads'r'us follow the general architecture and constraints described in the REST dissertation and add some domain specific constraints.

We only implement a HTTP interface to our resources which come with its own set of constraints. Most of our data resources (non-binary) uses the existing application/vnd.collection+json media type, commonly known as "Collection+JSON":

Collection+JSON is a JSON-based read/write hypermedia-type designed to support management and querying of simple collections. It is similar to the The Atom Syndication Format (RFC4287) and the The Atom Publishing Protocol (RFC5023) . However, Collection+JSON defines both the format and the semantics in a single media type. It also includes support for Query Templates and expanded write support through the use of a Write Template.

As the world progresses, new specifications, updates and enhancements arrive and we try to stay as much as possible in line. However, we will always remain backwards compatible with our own published specifications.

Make sure to check back regularly to get the latest version of this specification!

6.1 General Architecture Rules

These are general rules and principles used. They apply as long as a specific interaction/resource does not specify something else.

It is expected that the domain and objects that the resources describe evolve over time and thus new fields and link relations might be introduced later on. Clients must silently ignore unknown fieds and should not expect optional fields to be present.

6.2 Expected usage

It is assumed that clients are pre-programmed with a link to an ad list when starting to interact with us.

6.3 Ad Serialization Inside Collection+JSON

6.3.1 Data Fields

When serializing an ad inside a Collection+JSON, these fields are available:

In addition to the link relations specified by Collection+JSON, we use the picture relation to reference pictures that are related to the current resource.

6.3.4 Example

{ "collection" :
  {
    "version": "1.0",
    "href": "http://localhost:3000/ads",

    "links": [
      {"rel": "self", "href": "http://localhost:3000/ads"}
      {"rel": "collection", "href": "http://localhost:3000/ads"}
      {"rel": "feed", "href": "http://localhost:3000/ads.atom"}
    ],

    "items": [
      {
        "href" : "...",
        "data" : [
          {"name" : "title", "value" : "Nice house for sale!", "prompt" : "Title"},
          {"name" : "body", "value" : "Four rooms, huge bath.", "prompt" : "Ad Body"}
        ],
        "links" : [
          {"rel" : "add-picture", "href" : "..."}
          {"rel" : "picture", "href" : "...", "render" : "image"}
          {"rel" : "picture", "href" : "...", "render" : "image"}
        ]
      },
      ...
    ]
  }
}

6.4 Single Ad vs List of Ad Resources

As Collection+JSON does not have a way to send a single item only the context of the request specifies if the list will include one or more items.