The Zoom/Embed Pattern

A concern for many modern APIs is how to efficiently serve data to devices operating with constrained resources – either limited network connectivity, limited memory or both.

In terms of limited connectivity, a fully normalized set of resources offered by a server may ultimately result in several calls in order for a client to access all of the data they need. As noted, however, the amount of data served by each call should be limited only to the information related to the requested resource.

In a memory-constrained environment, the amount of data returned and parsed should be limited to the minimum set of data required to accomplish the requested task. In this situation, multiple calls to retrieve data in more manageable chunks may be preferable to fewer calls containing more data.

The “Zoom/Embed” pattern has emerged to address both of these issues – allowing clients to have greater control over the data they receive while reducing the number of requests made to the server.

The Zoom/Embed pattern provides for finer grained control over the data returned by allowing the developer to specify that one or more resources related to the requested resource be returned embedded within the response. While this can add significantly to the response payload a client receives, it gives the client developer an opportunity to decide whether that additional payload provides better performance over making additional calls.

For example, a Products resource may include a link to its manufacturer:

{
	"data":[{
		"products": [
		 	{
               "product_id": "76124",
               "name": "The Amazing Widget",
               "weight": "7.2 oz",
               ...
			   "_links": [
			   		{
						"rel": "self",
						"href": "http://api.example.com/v1/products/76124",
						"method": "GET"
					},
					{
						"rel": "http://api.example.com/v1/manufacturers/definition",
						"href": "http://api.example.com/v1/manufacturers/7",
						"method": "GET"
					},
					...
			   ]
          	}
		]
	}]
}

Retrieving the Product and its associated Manufacturer would typically require two calls. In an environment where it’s more expensive to construct a network connection than to exchange data, the Zoom/Embed pattern can reduce this to a single call by including the appropriate “rel” value in the “zoom” parameter:

GET /products/76124?zoom=http://api.example.com/v1/manufacturers/definition

Calling this should return the same response as before, with the related Manufacturer resource embedded within the response:

{
	"data":[{
		"products": [
		 	{
               "product_id": "76124",
               "name": "The Amazing Widget",
               "weight": "7.2 oz",
               ...
			   "_links": [
			   		{
						"rel": "self",
						"href": "http://api.example.com/v1/products/76124",
						"method": "GET"
					},
					{
						"rel": "http://api.example.com/v1/manufacturers/definition",
						"href": "http://api.example.com/v1/manufacturers/7",
						"method": "GET"
					},
					...
			   ],
			   "_embeds" : {
			   		"manufacturers": [
						{
							"name": "Oscorp, Inc.",
							...
							"_links": [
								{
									"rel": "self",
									"href": "http://api.example.com/v1/manufacturers/7",
									"method": "GET"
								}
								...
							]
						}
					]
			   }
          	}
		]
	}]
}

You may also request multiple related resources in a single call by simply adding them to the zoom parameter separated by commas. Note that this only works when using the GET verb to request data.

The use of the Zoom/Embed pattern does violate the rule that all URIs should be discoverable directly through calls to related endpoints. However, the flexibility it provides to client developers allowing them to control the amount of data they retrieve during a call outweighs that concern.

Leave a Reply

Your email address will not be published. Required fields are marked *