Contents

URL.Template

A template for constructing a URL from variable expansions.

Declaration

struct Template

Overview

This is an template that can be expanded into a URL by calling URL(template:variables:).

Templating has a rich set of options for substituting various parts of URLs. See RFC 6570 for details.

Example 1

let template = URL.Template("http://www.example.com/foo{?query,number}")!
let url = URL(
    template: template,
    variables: [
        .query: "bar baz",
        .number: "234",
    ]
)

extension URL.Template.VariableName {
    static var query: URL.Template.VariableName { .init("query") }
    static var number: URL.Template.VariableName { .init("number") }
}

The resulting URL will be

http://www.example.com/foo?query=bar%20baz&number=234

Usage

Templates provide a description of a URL space and define how URLs can be constructed given specific variable values. Their intended use is, for example, to allow a server to communicate to a client how to construct URLs for particular resources.

For each specific resource, an API contract is required to clearly define the variables applicable to that resource and its associated template. For example, such an API contract might specify that the variable query is mandatory and must be an alphanumeric string while the variable number is optional and must be a positive integer if provided. The server could then provide the client with a template such as http://www.example.com/foo{?query,number}, which the client can subsequently use to substitute variables accordingly.

An API contract is necessary to define which substitutions are valid within a given URL space. There is no guarantee that every possible expansion of variable expressions corresponds to an existing resource URL; indeed, some expansions may not even produce a valid URL. Only the API specification itself can determine which expansions are expected to yield valid URLs corresponding to existing resources.

Example 2

Here’s an example, that illustrates how to define a specific set of variables:

struct MyQueryTemplate: Sendable, Hashable {
    var template: URL.Template

    init?(_ template: String) {
        guard let t = URL.Template(template) else { return nil }
        self.template = t
    }
}

struct MyQuery: Sendable, Hashable {
    var query: String
    var number: Int?

    var variables: [URL.Template.VariableName: URL.Template.Value] {
        var result: [URL.Template.VariableName: URL.Template.Value] = [
            .query: .text(query)
        ]
        if let number {
            result[.number] = .text("\(number)")
        }
        return result
    }
}

extension URL.Template.VariableName {
    static var query: URL.Template.VariableName { .init("query") }
    static var number: URL.Template.VariableName { .init("number") }
}

extension URL {
    init?(
        template: MyQueryTemplate,
        query: MyQuery
    ) {
        self.init(
            template: template.template,
            variables: query.variables
        )
    }
}

Topics

Structures

Initializers