Yesterday I was attending the "RAML" workshop at the API Strategy konference. In this workshop the speakers introduced a very simple little Web API; It allowed a customer to GET a (shipment) quote and afterwards create (POST) an actual shipment request based on the quote.
I decided that it could be fun to hypermedia-ize the example and show how it could be represented using the media type Mason. So here we go :-)
The first step is to ask for a quote; the customer has a package of some sort and needs to ship it from A to B, so he access the shipment service and asks for a quote (a price) given the size, weight, origin and destination for the package.
In the original example you could ask for a quote by issuing a GET request to /quote. But I believe that asking for a quote would result in a concrete quote being created and stored in the system as a separate resource to access later on, either by the customer or by the customer service of the shipment company. So I would rather go for a POST of a quote request followed by a redirect to the newly created quote.
At this point we could either document how to POST such a quote - or we could tell the client how to do it using hypermedia controls - and obviously I would go for the later. So lets ask the service for instructions and issue a GET /quote request. The output is a Mason document with suitable hypermedia controls embedded in it:
{
"@namespaces":
{
"myth":
{
"name": "http://mythological-shipment.com/api/rel-types"
}
},
"@actions":
{
"myth:quote":
{
"type": "json",
"method": "POST",
"href": "http://mythological-shipment.com/api/quote",
"title": "Ask for a quote",
"description": "Ask for a quote by posting package details. Weight is in kilograms, volume in cubic decimeters, origin and destination must be known identifiers for airports.",
"schemaUrl": "... URL to JSON schema describing the request ..."
}
}
}
The client reads this action specification, encodes the package details in JSON and POST it to the URL of the "href" property. As a result the service creates a new quote resource and redirects the client to it:
Request:
POST http://mythological-shipment.com/api/quote HTTP/1.1
content-type: application/json
{
"weight": 2.3,
"volume": 4,
"origin": "CPH",
"destination": "AMS"
}
Response:
201 Created
Location: http://mythological-shipment.com/api/quotes/myqo-129-gyh
Now the client can GET the newly created quote to get further instructions of how to accept the quote. The result is again a Mason representation of the quote itself plus hypermedia controls for accepting the quote:
{
"id": "myqo-129-gyh",
"weight": 2.3,
"volume: 4,
"origin": "CPH",
"destination": "AMS":
"price": 12,
"@links":
{
"self":
{
"href": "http://mythological-shipment.com/api/quotes/myqo-129-gyh"
}
},
"@actions":
{
"myth:accept-quote":
{
"type": "POST",
"href": "http://mythological-shipment.com/api/quotes/myqo-129-gyh/state",
"template":
{
"accepted": "yes"
}
}
}
}
As you can see the quote has a "self" link identifying the location of the quote resource. It also have a "accept-quote" action that instructs the client about how to accept the quote. In this case all the client has to do is to POST a predefined JSON value to http://mythological-shipment.com/api/quotes/myqo-129-gyh/state.
The result of accepting a quote is that it is converted to a sales order (in lack of better domain understanding - there's probably a better word for it). So the accept-quote operation results in a redirect to the newly create sales order which the client can GET:
{
"id": "myqo-129-gyh",
"weight": 2.3,
"volume: 4,
"origin": "CPH",
"destination": "AMS":
"price": 12,
"@links":
{
"self":
{
"href": "http://mythological-shipment.com/api/orders/myqo-129-gyh"
},
"myth:quote":
{
"href": "http://mythological-shipment.com/api/quotes/myqo-129-gyh"
},
"myth:shipment-label":
{
"href": "http://mythological-shipment.com/api/quotes/myqo-129-gyh/label",
"type": "application/pdf"
}
}
}
At last the customer needs a shipment label to print out and stick onto the package. All it has to do is to follow the "myth:shipment-label" link and GET the PDF. Thats it.
/Jørn