Oliver McPhee
Oliver McPhee

Reputation: 1056

How to correctly use HAL (Hypermedia Application Language) _embedded?

I am building a REST API that exposes information about online courses to users. Here is the general structure of a course:

Course > Units > Lessons > Activities

I'm trying to make my JSON response structure HAL compliant, but i'm unsure if i'm doing it correctly.

Which of the following is correct:

{
  “kind”: “clms#course”,
  “id”: long,
  “course-name”: string,
  “course-icon”: string,
  “product-name”: string,
  “product-icon”: string,
  “_links”: {
    “self”: {“href” : string}, 
    “unitlist”: {“href” : string} // This is a link to list of units for the course.
  }
}

Or is the link to the list of units an _embedded resource?

{
      “kind”: “clms#course”,
      “id”: long,
      “course-name”: string,
      “course-icon”: string,
      “product-name”: string,
      “product-icon”: string,
      “_links”: {
        “self”: {“href” : string}, 
      }
      "_embedded": {
        “unitlist”: {“href” : string} // This is a link to list of units for the course.
      }
    }

Or are both wrong!? Any help appreciated.

Cheers, Ollie

Upvotes: 1

Views: 995

Answers (1)

Chris DaMour
Chris DaMour

Reputation: 4010

Few things. Let me take you through the process, and it might help.

Start with just the links and their relationships. There's a course, it has units. So each unit relates to a course as a unit. use that as your relationship name. so:

{
  “kind”: “clms#course”,
  “id”: long,
  “course-name”: string,
  “course-icon”: string,
  “product-name”: string,
  “product-icon”: string,
  “_links”: {
    “self”: {“href” : string}, 
    “unit”: [
       {“href” : url-of-first-unit},
       {“href” : url-of-second-unit},
       {“href” : url-of-third-unit},
       ...
    ]
  }
}

but unit is not an IANA registered link relationship, so it should actually be a URI, or curried to a URI:

“_links”: {
    “self”: {“href” : string},
    "curies" : [
       {"href" : "http://youndomain/rels/{rel}", name : "x" }
    ],
    “x:unit”: [
       {“href” : url-of-first-unit},
       {“href” : url-of-second-unit},
       {“href” : url-of-third-unit},
       ...
    ]
  }

that's a little confusing, but it makes it so your unit is "namespaced" and it's own thing which is good.

Now realize that retrieving all of those units individually would be painful. I'll assume that in your UI you want to show the units right along with the courses, so HAL let's you embed those relationships:

{
  “kind”: “clms#course”,
  “id”: long,
  “course-name”: string,
  “course-icon”: string,
  “product-name”: string,
  “product-icon”: string,
  “_links”: {
    “self”: {“href” : string}, 
    "curies" : [
       {"href" : "http://youndomain/rels/{rel}", name : "x" }
    ],
    “x:unit”: [
       {“href” : url-of-first-unit},
       {“href” : url-of-second-unit},
       {“href” : url-of-third-unit},
       ...
    ]
  },
  "_embedded" : {
    “x:unit”: [
       { some json representing the unit located at url-of-first-unit},
       { some json representing the unit located at url-of-second-unit},
       { some json representing the unit located at url-of-third-unit},
       ...
    ]
  }
}

Now a client can get the unit's my checking embedded instead of checking links. In fact since it's embedded, there's really no reason to include the links anymore (unless you know a client is depending on them):

{
  “kind”: “clms#course”,
  “id”: long,
  “course-name”: string,
  “course-icon”: string,
  “product-name”: string,
  “product-icon”: string,
  “_links”: {
    “self”: {“href” : string}, 
    "curies" : [
       {"href" : "http://youndomain/rels/{rel}", name : "x" }
    ],
  },
  "_embedded" : {
    “x:unit”: [
       { some json representing the unit located at url-of-first-unit},
       { some json representing the unit located at url-of-second-unit},
       { some json representing the unit located at url-of-third-unit},
       ...
    ]
  }
}

So now the client has them available as an embedded resource and does not need to retrieve the resources with http requests.

Overall i'd suggest starting with links to everything, and optimize for your use cases by embedded resources.

Few extra notes:

  • If you really have a need to collect all the units together in a single resource, perhaps consider that as a page with embedded item[s] which would be the units. The relationship from course to page of unit[s] would probably be x:units.
  • Avoid having an id field on your resource unless the id is something that is known to the outside world. A self link is a much better external id, as it's a URL and is easier to turn into an actual resource.
  • i prefer profile links as opposed to a "kind" field, especially when it looks like an enum. check out https://www.rfc-editor.org/rfc/rfc6906

Upvotes: 1

Related Questions