Skip to content

HAL (Hypertext Application Language)

TypedRest supports extracting links from response bodies using the HAL specification. HAL provides a consistent format for embedding links and embedded resources within JSON responses.

HAL format

HAL adds a _links object to JSON responses containing links organized by relation type:

{
    "id": 123,
    "name": "John Doe",
    "_links": {
        "self": { "href": "/users/123" },
        "orders": { "href":  "/users/123/orders" },
        "search": { "href":  "/users/{id}", "templated": true }
    }
}

Content type

TypedRest recognizes HAL responses by the application/hal+json content type:

When this content type is present, TypedRest automatically parses the _links object and makes the links available through the standard link resolution methods.

After receiving a HAL response, you can resolve links just like with HTTP Link headers:

await endpoint.ReadAsync();

// Resolve a single link
Uri ordersUri = endpoint.Link("orders");

// Resolve a templated link
Uri userUri = endpoint.LinkTemplate("search", new { id = "456" });
endpoint.read();

// Resolve a single link
URI ordersUri = endpoint.link("orders");

// Resolve a templated link
URI userUri = endpoint.linkTemplate("search", Map.of("id", "456"));
endpoint.read()

// Resolve a single link
val ordersUri = endpoint.link("orders")

// Resolve a templated link
val userUri = endpoint.linkTemplate("search", mapOf("id" to "456"))
await endpoint.read();

// Resolve a single link
const ordersUri = endpoint.link("orders");

// Resolve a templated link
const userUri = endpoint.linkTemplate("search", { id: "456" });

HAL supports multiple links for the same relation type using an array:

{
    "_links": {
        "item": [
            { "href": "/items/1", "title": "First Item" },
            { "href": "/items/2", "title": "Second Item" }
        ]
    }
}

Retrieve all links with GetLinks:

var items = endpoint.GetLinks("item");
foreach (var (uri, title) in items)
{
    Console.WriteLine($"{title}: {uri}");
}
List<Link> items = endpoint.getLinks("item");
for (Link link : items) {
    System.out.println(link.getTitle() + ": " + link.getUri());
}
val items = endpoint.getLinks("item")
for (link in items) {
    println("${link.title}: ${link.uri}")
}
const items = endpoint.getLinks("item");
for (const { uri, title } of items) {
    console.log(`${title}: ${uri}`);
}

HAL links can be marked as templates with the templated property:

{
    "_links": {
        "find": {
            "href": "/users{?name,email}",
            "templated": true
        }
    }
}
var findUri = endpoint.LinkTemplate("find", new { name = "John", email = "john@example.com" });
// Result: /users?name=John&email=john%40example.com
URI findUri = endpoint.linkTemplate("find", Map.of("name", "John", "email", "john@example.com"));
// Result: /users?name=John&email=john%40example.com
val findUri = endpoint.linkTemplate("find", mapOf("name" to "John", "email" to "john@example.com"))
// Result: /users?name=John&email=john%40example.com
const findUri = endpoint.linkTemplate("find", { name: "John", email: "john@example.com" });
// Result: /users? name=John&email=john%40example.com