hal+json embedded inside embedded (Multiple/Nested embedded)

HAL (Hypertext Application Language) is a new standard for RESTFUL web services. The HAL rfc is still in draft at the time of this post, however, the main goal of the HAL standard is to provide a more convenient and easy way to expose resources within your API. The _links reserved property allows resources to link to other resources via a href. Any client consuming the API can simply follow the links served by the back end. See below for an example;

{
    "_links": {
        "self": { "href": "/" },
        "contact": { "href": "/contact" }
        "about": { "href": "/about" }
    },
    ...
}

When sending a GET request on a collection to an API that uses HAL, a number of resources will be populated in the _embedded property. This is another reserved property used by HAL. A collection of embedded resources may look like below;

{
    "_links": {
        "self": { "href": "/invoices" }
    },
    "_embedded": {
        "invoices": [
            {
                "_links": {
                    "self": { "href": "/invoice/1" }
                },
                "id": 1,
                "total": 2.99,
                "no_items": 1
            },
            {
                "_links": {
                    "self": { "href": "/invoice/2" }
                },
                "id": 2,
                "total": 94.87,
                "no_items": 7
            }
        ]
    }
}

Now, assume we want to have an _embedded collection of resources inside each invoice resource to list the products ordered. I’m not aware of anywhere in the HAL spec that explicitly states nested embedded is valid HAL. Arguably, the diagram in the HAL specification by Mike Kelly suggests embedded resources are recursive. The major issue with not supporting nested embedded resources is the client consuming the API has to perform a lot of “round trips” to request each embedded resource individually via the resource href link. Take a look at the payload below illustrating nested embedded resources.

{
    "_links": {
        "self": { "href": "/invoices" }
    },
    "_embedded": {
        "invoices": [
            {
                "_links": {
                    "self": { "href": "/invoice/1" }
                },
                "_embedded": {
                    "items": [
                        { "_links": { "self": { "href": "/product/1" }}, "id": 1, "name": "Super cheap Macbook Pro", "price": 2.99 }
                    ]
                },
                "id": 1,
                "total": 2.99,
                "no_items": 1
            },
            {
                "_links": {
                    "self": { "href": "/invoice/2" }
                },
                "_embedded": {
                    "items": [
                        { "_links": { "self": { "href": "/product/2" }}, "id": 2, "name": "Raspberry Pi", "price": 34.87 },
                        { "_links": { "self": { "href": "/product/3" }}, "id": 3, "name": "Random product", "price": 30 },
                        { "_links": { "self": { "href": "/product/4" }}, "id": 4, "name": "More randomness", "price": 30 }
                    ]
                },
                "id": 2,
                "total": 94.87,
                "no_items": 3
            }
        ]
    }
}

Now we list each product item as an embedded resource in the already existing invoice resource. This is a great way of exposing the API for additional resources without having to make additional requests to retrieve the resources from the server. Imagine having to make a request for each embedded product inside the invoice resource – this would hammer the server and probably kill it when under heavy load.

So there we have it, nested embedded resources is indeed valid HAL and doesn’t break any of the conventions or spec set out in the rfc. I wanted to clarify this because there’s been a number of discussions where people aren’t sure whether nested embedded resources is officially valid HAL. To back this up, I asked Mike Kelly himself via Twitter;

https://twitter.com/mikekelly85/status/489105600685809664

Leave a comment