Skip to content

URI templates

TypedRest supports URI templates as defined in RFC 6570. URI templates allow you to construct URIs dynamically by substituting variables into a template string.

How URI templates work

A URI template contains placeholders (variables) that are replaced with actual values at runtime. For example:

  • Template: /users/{id} with {id: "123"}/users/123
  • Template: /search{?q,limit} with {q: "test", limit: 10}/search?q=test&limit=10

Server-provided templates

The server can provide URI templates via the HTTP Link header:

Link: </users/{id}>; rel=user; templated=true

Or in HAL:

{
    "_links": {
        "user": {
            "href": "/users/{id}",
            "templated": true
        }
    }
}

Resolving templates

Use the LinkTemplate method to resolve a template with variables:

// After receiving a response with the link template
var userUri = endpoint.LinkTemplate("user", new { id = "123" });
// Result: http://example.com/users/123

// With query parameters
var searchUri = endpoint.LinkTemplate("search", new { q = "test", limit = 10 });
// Result: http://example.com/search?q=test&limit=10

// Using a dictionary
var variables = new Dictionary<string, object> { ["id"] = "123" };
var uri = endpoint.LinkTemplate("user", variables);
// After receiving a response with the link template
URI userUri = endpoint.linkTemplate("user", Map.of("id", "123"));
// Result: http://example.com/users/123

// With query parameters
URI searchUri = endpoint.linkTemplate("search", Map.of("q", "test", "limit", 10));
// Result: http://example.com/search?q=test&limit=10
// After receiving a response with the link template
val userUri = endpoint.linkTemplate("user", mapOf("id" to "123"))
// Result: http://example.com/users/123

// With query parameters
val searchUri = endpoint.linkTemplate("search", mapOf("q" to "test", "limit" to 10))
// Result: http://example.com/search?q=test&limit=10
// After receiving a response with the link template
const userUri = endpoint.linkTemplate("user", { id: "123" });
// Result: http://example.com/users/123

// With query parameters
const searchUri = endpoint.linkTemplate("search", { q: "test", limit: 10 });
// Result: http://example.com/search?q=test&limit=10

You can register default link templates that will be used when the server doesn't provide a template for a specific relation type:

class MyEndpoint : EndpointBase
{
    public MyEndpoint(IEndpoint referrer, string relativeUri) 
        : base(referrer, relativeUri)
    {
        // Set a default template for the "child" relation
        SetDefaultLinkTemplate("child", "./{id}");
    }
}
class MyEndpoint extends AbstractEndpoint {
    public MyEndpoint(Endpoint referrer, String relativeUri) {
        super(referrer, relativeUri);
        // Set a default template for the "child" relation
        setDefaultLinkTemplate("child", "./{id}");
    }
}
class MyEndpoint(referrer: Endpoint, relativeUri: String) : AbstractEndpoint(referrer, relativeUri) {
    init {
        // Set a default template for the "child" relation
        setDefaultLinkTemplate("child", "./{id}")
    }
}
class MyEndpoint extends Endpoint {
    constructor(referrer: Endpoint, relativeUri: string) {
        super(referrer, relativeUri);
        // Set a default template for the "child" relation
        this.setDefaultLinkTemplate("child", "./{id}");
    }
}

Built-in defaults

Collection and Indexer endpoints automatically set a default link template of ./{id} for the child relation. This allows you to access individual elements by ID without the server explicitly providing a link template.