0

Forgive me as I am still new to this RESTFUL thing, I have been reading blogs etc... and they all have got different implementations/guidelines really, only real guideline is the Richardson Maturity Model that specifies what Hypermedia is.

I know the benefits of a Hypermedia design is to have links with annotations driving machine/user interaction via a root URL, and it will be evolvable like when the links change, enhancing caching with idempotent/safe http verbs etc...

I am trying to design a RESTFUL API Webservice and I am planning to use a GENERIC MEDIA TYPE maybe like HAL or Collection+Json or Siren etc... Or possibly create my own Media Type which I do not think I want to go into right now...

With a generic media type, I would have a payload, a data structure or DTO object, whatever you call it, like "Application Model with many Applicants Models with Many Addresses etc..."

1) Do I have to specify the data structure definition somewhere? or a form template of some sort? I have seen some examples with where they put their definition of that data in a human readable format in like "someurl/doc? Or should we use something like json schema?

2) Some examples I have seen decorated their data items with a type in a link from vcard/foaf etc... eg. "name": "http://xmlns.com/foaf/0.1/name". What does that mean? Some examples I see have like references to their someurl/doc#name for describing the name object etc...

3) Does it mean that if the payload of the Application Model changes, the interpreter of the contract changes? And therefore all clients break as before, like in SOAP?

4) One other alternative, I think I can have an evolvable item structure, like the collection+json item object with Name,Value,Prompt that forms the actual structure, that way there will be minimal contract changes on the client end consuming it.

Please advice on how I should design my object, basically say I have an APPLICATION OBJECT with multiple APPLICANTS with MULTIPLE ADDRESSES to simplify the question.

Josh

Joshscorp
  • 1,832
  • 4
  • 22
  • 42

1 Answers1

3

The best current practice is to avoid creating new content types wherever possible, so you're right to shy away from that.

  1. Depends on your audience. Use whatever would be easiest for them to consume. Are they generic automated agents, which can understand a schema, or are they developers working specifically to your API. You will always need human-readable docs anyway, so I'd start there. If you choose to accept application/x-www-form-urlencoded request bodies, then a HTML form would be a great way of providing a working template.
  2. This defines the "type" of a field. So name is a foaf:name tells you that the field called name contains a value of type http://xmlns.com/foaf/0.1/name. You should read up about RDF, the resource description format, and look at the representations like Turtle and N3 which should make this clearer. The concept of relations that are URIs (instead of simple strings) comes from there, though link relations are not the same as RDF properties such as owl:sameAs or foaf:name. Both are represented as edges in a directed graph.
  3. Please explain more, do you mean fields added/removed or a completely different content type? I would argue that the latter is a different resource and should have a different URI. Your clients will need to either understand or be able to ignore any future changes you make to your resources.
  4. All of the content types you suggested should be evolvable in this manner. That is exactly the premise of HATEOAS.

Your design appears to me to be a simple tree structure with one root resource, containing a list of collections, each containing a list of leaf resources. I seem to be missing something here because there's nothing complicated in that.

I am going to assume that by Applicant you mean a person applying for a job, and by Address you mean somewhere they live or work (as opposed, say, to an email address). Some of the below may be obvious but I am including it for other readers who may come across this question.

An example implementation, using HAL, would be:

Request:

GET / HTTP/1.1
Host: example.com
Accept: application/hal+json

Response:

HTTP/1.1 200 OK

{ "_links": {
    "self": { "href": "/" },
    "http://example.com/docs/applicant": [
      { "href": "/applicant1" },
      { "href": "/applicant2" },
      { "href": "/applicant3" }]
} }

The client would then look for hyperlinks that have the relation http://example.com/docs/applicant, which is just a string and could be fishmonkeygiraffe if you wanted - making the string be a http URL allows client developers to find your documentation more easily, as well as scoping relationships by prefixing it with a unique string: your own domain. The response format could be any hypertext-capable format, such as HTML, as long as the client knows how to find the hyperlinks within it (<LINK> and <A> elements), or you could return them in a HTTP Link header, but then the client is responsible for storing them if it needs to write the retrieved resource to disk.

The client then requests the one it wants to look at:

GET /applicant1 HTTP/1.1
Host: example.com
Accept: application/hal+json

Response:

HTTP/1.1 200 OK

{ "_links": {
    "self": { "href": "/applicant1" },
    "http://example.com/docs/applicant-address": [
      { "href": "/applicant1/address1" },
      { "href": "/applicant1/address2" },
      { "href": "/applicant1/address3" }]
} }

Obviously "applicant1" can be anything you like, e.g. "applicants/1" or "vacancies/sweet-manager/applicants/dave-smith". The client just follows the URL it is given.

The client then picks a hyperlink of type http://example.com/docs/applicant-address to retrieve:

GET /applicant1/address1 HTTP/1.1
Host: example.com
Accept: application/hal+json

Response:

HTTP/1.1 200 OK

{ "_links": {
    "self": { "href": "/applicant1/address1" },
    "edit-form": { "href": "/applicant1/address1/edit" },
    "http://example.com/docs/applicant": { "href": "/applicant1" }
  },

  "street": "5 Dungeon Drive",
  "town": "Snotty Hill",
  "county": "London",
  "postcode": "NE5 2LT",
  "country": "GB",
}

Now the client wants to amend the address, so it follows the hyperlink with the relation "edit-form": (see IANA link relations)

GET /applicant1/address1/edit HTTP/1.1
Host: example.com
Accept: text/html

Response:

HTTP/1.1 200 OK

<!DOCTYPE HTML>
<form action="/applicant1/address1" method="POST">
  <input name="street" value="5 Dungeon Drive">
  et cetera
</form>

Resulting in:

POST /applicant1/address1 HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

street=5%20Dungeon%20Drive&...

I have used HAL because HAL is like a JSON version of XML+XLink, just simpler to type in SO examples ;) i.e. it's a hypermedia-capable common parse format, nothing more. All interaction is guided by link relations. Web browsers know what to do with a rel="stylesheet" link because it knows what that relation means. The IANA-defined list of link relations cited above are ones you should choose from first (item and collection are very useful), and then if what you are looking for is not specific enough, try to find a public list of link relations relevant to your sector (for example see what API the market leader publishes) and re-use those if possible. This will allow tools to become interoperable because they are all looking for the same link relations. Your Dublin Core example in the question is a similar repository of publicly defined RDF Properties.

For hyperlinks, the coupling (contract) is not be between the client and your site, but the client and a set of relations. The relations should be as well-known as possible (this is what Wikipedia means when it says "a generic understanding of hypermedia").
For resource fields, if you intend your resource to be processed generically, then I would recommend an RDF-based solution, using well-known RDF Properties that map closely to your domain of business. Several RDF serialisations into JSON exist but at the moment there is no clear leader. You would probably be better off supporting just XML at this point. The blog post JSON to RDF in six easy steps may be insightful as a way to learn the basics of RDF.

Nicholas Shanks
  • 10,623
  • 4
  • 56
  • 80
  • 3) For example, if you have a Model/DTO whatever that has 3 fields, id, name, description for example in the payload before. Now you want to change it to id, other-name, other-description, won't the client code break? As in SOAP, when WSDL Changes, aka contract changed, won't you have you have to redo your client side code? – Joshscorp Jun 12 '13 at 13:20
  • Can you give me an example of the simple payload you talk about? Say Application as the top level with Name, Date Submitted, Description, Type, fields, would they all need the RDF you talked about in 2)? – Joshscorp Jun 12 '13 at 13:27
  • 1
    if you CHANGE name to other-name, then yes, things looking for "name" will break. But that's true of any format and any implementation architecture. You would need to send both the old label and the new one. I will add an example to the answer. – Nicholas Shanks Jun 12 '13 at 14:02
  • Thanks for the great example...but it still is very coupled in my opinion...in wikipedia...definition of HATEOAS is defined as A REST client needs no prior knowledge about how to interact with any particular application or server beyond a generic understanding of hypermedia. Contrast this with e.g. a service-oriented architecture (SOA), where clients and servers interact through a fixed interface shared through documentation or an interface description language (IDL). So changing name to other-name = interface change to me, aka not HATEOAS? – Joshscorp Jun 12 '13 at 23:21
  • My understanding so far, HAL which is the Generic MEDIA TYPE, needs to be documented and understood by the client, once implemented, it should be able to evolve freely without changing the client side, including the payload, which I am very confused about even in your example, you need specific knowledge of the payload format, interface, IDL, documentation etc..., which to me is the opposite to the definition of HATEOAS? In your example, client will break if you renamed "Street" in the address payload to something else. – Joshscorp Jun 12 '13 at 23:25
  • @Joshscorp HAL is fairly unique in that to understand "payload" of embedded representations you use the link relation specification with which the embedded resource is associated to. Therefore, the client doesn't need to document the specific instance of a HAL representation, but it does need to document link relations that say specifically what properties are potentially embedded. – Darrel Miller Jun 13 '13 at 12:41
  • @Joshscorp If you change the embedded payload to use `other-name` instead of 'name' then you would need to create a new link relation so that the client knows that something has changed. REST does not remove coupling, it merely focuses the coupling around media types and link relations. By doing that it makes it easier to manage the coupling. And because link relations and media types are always included in the representation, the client is ALWAYS aware of if it understands the information or not. There can be no breaking changes without the client finding out. – Darrel Miller Jun 13 '13 at 12:48
  • "REST does not remove coupling, it merely focuses the coupling around media types and link relations." <- Yes! What Darrel said. He's the expert here :) – Nicholas Shanks Jun 13 '13 at 12:50
  • This is a great answer, however, I personally would soften the "avoid creating new media types". I'd rather see too many overly specific media types than people tunneling semantics via generic media types. There is a balance, but I believe there are lots of opportunities for creating really useful re-usable media types that we are not taking advantage of. – Darrel Miller Jun 13 '13 at 12:51
  • @DarrelMiller Perhaps. My life experience generally guides me towards an attitude that specifics derived from oft-used generic patterns (ie. a "pave the cowpath"-like philosophy) have been more successful than trying to go the other way ("build it and they will come", ivory tower specifications being pushed onto market sectors.) The latter often only works if there is a behemoth vendor pushing their proprietary syntax. – Nicholas Shanks Jun 13 '13 at 13:16
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/31720/discussion-between-darrel-miller-and-nicholas) – Darrel Miller Jun 13 '13 at 13:57