Skip to main content

Crate templated_uri

Crate templated_uri 

Source
Expand description

Standards-compliant URI handling with templating, safety validation, and data classification.

This crate provides comprehensive URI manipulation capabilities designed for HTTP clients and servers that need type-safe, efficient, and data classification-aware URI handling. It builds on top of the standard http crate while adding additional safety guarantees, templating capabilities, and data classification features.

§Core Types

The crate centers around several key abstractions:

  • Uri - Flexible URI type with endpoint and path/query components
  • BaseUri - Lightweight type representing scheme and authority (no path/query)
  • TemplatedPathAndQuery - RFC 6570 Level 3 compliant URI templating
  • UriSafe and UriSafeString - Generic newtype wrapper proving a value is safe for URI components by not containing any reserved characters

§Basic Usage

§Simple URI Construction

use templated_uri::uri::{PathAndQuery, TargetPathAndQuery};
use templated_uri::{BaseUri, Uri};

// Create an endpoint (scheme + authority only)
let base_uri = BaseUri::from_uri_static("https://api.example.com");

// Create a path (can be static for zero-allocation)
let path: TargetPathAndQuery = TargetPathAndQuery::from_static("/api/v1/users");

// Combine into complete URI
let uri = Uri::default().base_uri(base_uri).path_and_query(path);
assert_eq!(
    uri.to_string().declassify_ref(),
    "https://api.example.com/api/v1/users"
);

§Templated URIs

For dynamic URIs with variable components, use the templating system:

use templated_uri::{BaseUri, TemplatedPathAndQuery, Uri, UriSafeString, templated};

#[templated(template = "/users/{user_id}/posts/{post_id}", unredacted)]
#[derive(Clone)]
struct UserPostPath {
    user_id: u32,
    post_id: UriSafeString,
}

let path = UserPostPath {
    user_id: 42,
    post_id: UriSafeString::encode("my-post"),
};

let uri = Uri::default()
    .base_uri(BaseUri::from_uri_static("https://api.example.com"))
    .path_and_query(path);

§URI Safety Guarantees

The UriSafe<T> newtype wraps values that are guaranteed to contain only URI-safe characters. This prevents common URI injection vulnerabilities:

use templated_uri::UriSafeString;

// This will succeed - encodes unsafe characters into a URI-safe format
let unsafe_string = UriSafeString::encode("hello world?foo=bar");
assert_eq!(unsafe_string.as_str(), "hello%20world%3Ffoo%3Dbar");

// This will succeed - contains only safe characters
let safe = UriSafeString::try_new("hello-world_123").unwrap();
assert_eq!(safe.as_str(), "hello-world_123");

// try_new() fails on URI-reserved characters
let unsafe_string = UriSafeString::try_new("hello world?foo=bar");
assert!(unsafe_string.is_err());

Built-in safe types include numeric types (u32, u64, etc.), Uuid (with the uuid feature), IP addresses, and validated UriSafeString instances.

§Telemetry Labels

For complex templates, use the label attribute to provide a concise identifier for telemetry. When present, the label takes precedence over the template string.

use templated_uri::{UriSafeString, templated};

#[templated(
    template = "/{org}/users/{user_id}/reports/{report_type}",
    label = "user_report",
    unredacted
)]
struct ReportPath {
    org: UriSafeString,
    user_id: UriSafeString,
    report_type: UriSafeString,
}

§Data Classification

The crate integrates with data_privacy to track data sensitivity levels in URIs. This is particularly important for compliance and data security:

use data_privacy::Sensitive;
use templated_uri::{UriSafeString, templated};

#[templated(template = "/{org_id}/user/{user_id}/")]
#[derive(Clone)]
struct UserPath {
    #[unredacted]
    org_id: UriSafeString,
    user_id: Sensitive<UriSafeString>,
}

§RFC 6570 Template Compliance

The templating system implements RFC 6570 Level 3 URI Template specification. Supported expansions include:

  • Simple string expansion: {var}
  • Reserved string expansion: {+var}
  • Path segments: {/var}
  • Query parameters: {?var}
  • Query continuation: {&var}

Note: Fragment expansion ({#var}) from RFC 6570 is not supported because URI fragments are stripped by the http crate and ignored by HTTP clients.

Template variables must implement UriParam (except for reserved expansions) to ensure the resulting URI is valid.

§Integration with HTTP Ecosystem

This crate seamlessly integrates with the broader Rust HTTP ecosystem by re-exporting and building upon the standard http crate types. The resulting Uri can be converted to an http::Uri for use with HTTP clients and servers based on hyper like reqwest.

Modules§

uri
Types and traits that constitute a Uri.

Structs§

BasePath
The base of a Uri, like /foo.
BaseUri
An HTTP or HTTPS BaseUri representing a target location without path information.
Origin
Represents the origin of a URI, consisting of the scheme and authority components.
Uri
Represents a URI that can be used as a target for requests.
UriSafe
A wrapper that proves the inner value is safe for use in URI templates.
UriSafeError
Error returned when a string contains characters that are not safe for URI templates.
ValidationError
Represents errors that occur during URI validation.

Constants§

DATA_CLASS_UNKNOWN_URI
The privacy classification of an unknown URI.

Traits§

TemplatedPathAndQuery
Allows for the creation of URIs based on templates.
UriParam
Marks types usable from templates, e.g., /get/{foo}.
UriUnsafeParam
Marks types with possibly dodgy content usable from templates, e.g., /get/{+foo}.

Type Aliases§

UriSafeString
A URI-safe string whose content is guaranteed to contain only characters valid in URI templates as defined by RFC 6570.

Attribute Macros§

templated
Generates URI templating and data privacy implementations for structs and enums.

Derive Macros§

UriParam
Derives the UriParam trait for newtype wrappers around URI-safe types.
UriUnsafeParam
Derives the UriUnsafeParam trait for newtype wrappers with unrestricted characters.