There’s been some recent discussion on the hal-discuss mailing list around the ‘Zoom’ concept for embedding resources, which has prompted me to start exploring this area a little further with a view to potentially writing up a specification that can be applied to any media type that define a way of embedding resources. This blog post mostly serves as a narrative to document my own ideas and learnings and to collect comments and recommendations from others in order to arrive at a proposal that will work for (almost!) everyone.

At its most simple level, clients need a way of being able to take an existing resource with defined link relations and zoom (or expand) the current resource to include them in the response. This is primarily to avoid a second round trip to the server in order to retrieve the resource representation that the client is interested in seeing.

To illustrate the problem, I have provided an example (for the sake of brevity, I have only included relevant parts of the resource representation).

{
    "_links": {
        "http://.../rels/detail": {
            "href": "/example/1/detail"
        },
        "http://.../rels/misc": {
            "href": "/example/1/misc"
        },
        "self": {
            "href": "/example/1"
        }
    }
}

In the above example, imagine a scenario where the client that has requested this representation is actually interested in the resource found at the ‘http://…/rels/detail’ link relation. The client now has to make a second request to the server in order to get at the data it needs.

We can alleviate this by using a feature of the media type known as embedding – however it is impractical to embed every linked resource every time. We must provide a way of allowing the client to specify the resource it is interested in – and this is ‘Zoom’.

If we allow the ‘zoom’ (or ‘z’) parameter in the query string to be reserved for this purpose, we can request that the server embeds the link relation by performing a GET request on ‘http://…/example/1?zoom=http://…/rels/detail’. The server would then be given the instruction to embed the resource and return it all in the response.

{
    "_embedded": {
        "http://.../rels/detail": [
            {
                "_links": {
                    "self": {
                        "href": "/example/1/detail"
                    }
                },
                "firstname": "Ben",
                "lastname": "Longden"
            }
        ]
    },
    "_links": {
        "http://.../rels/detail": {
            "href": "/example/1/detail"
        },
        "http://.../rels/misc": {
            "href": "/example/1/misc"
        },
        "self": {
            "href": "/example/1"
        }
    }
}

If we wanted to embed two items, the zoom query parameter may accept multiple link relations separated by commas, i.e., http://…/example/1?zoom=http://…/rels/detail,http://…/rels/misc.

The HAL format also supports CURIE style links to shorten the length of link relations and abbreviate the link down to a ‘x:detail’ or ‘x:misc’ format. There is no reason to not support these shorter syntax link rels, if the CURIE can be resolved. Here is an example of ‘http://…/example/1/?zoom=x:detail’.

{
    "_embedded": {
        "x:detail": [
            {
                "_links": {
                    "self": {
                        "href": "/example/1/detail"
                    }
                },
                "firstname": "Ben",
                "lastname": "Longden"
            }
        ]
    },
    "_links": {
        "curies": {
            "href": "http://.../rels/{rel}",
            "name": "x",
            "templated": true
        },
        "self": {
            "href": "/example/1"
        },
        "x:detail": {
            "href": "/example/1/detail"
        },
        "x:misc": {
            "href": "/example/1/misc"
        }
    }
}

The above examples and narrative cover zoom at it’s most basic implementation – and this will fit many situations fairly well. However, this idea of partially embedding sub resources is not new – what we are seeking is a unified way of following this pattern so that a common approach can be applied to any media type that has the ability to embed resources.

Implementations of this pattern can be found ‘in the wild’ in a number of places – to varying levels of completeness. From simply being able to embed a resource in a representation through to being able to specify a DSL to allow clients to query data that’s returned (specifying a limit to the number of resources in an embedded collection, or filtering by values in an embedded collection.

I’ll write up some thoughts around querying and limiting embedded data in a future post – i’d like to keep things relatively simple for now, and dive deeper into what the possibilities are later!

Comments more than welcome below.