<div align="center">
<img src="./logo.png" alt="Templated Uri Logo" width="96">
# Templated Uri
[](https://crates.io/crates/templated_uri)
[](https://docs.rs/templated_uri)
[](https://crates.io/crates/templated_uri)
[](https://github.com/microsoft/oxidizer/actions/workflows/main.yml)
[](https://codecov.io/gh/microsoft/oxidizer)
[](../../LICENSE)
<a href="../.."><img src="../../logo.svg" alt="This crate was developed as part of the Oxidizer project" width="20"></a>
</div>
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`][__link0] - Flexible URI type with endpoint and path/query components
* [`BaseUri`][__link1] - Lightweight type representing scheme, authority, and optional base path ([`BasePath`][__link2])
* [`TemplatedPathAndQuery`][__link3] - RFC 6570 Level 3 compliant URI templating
* [`UriSafe`][__link4] and [`UriSafeString`][__link5] - Generic newtype wrapper proving a value is safe for URI components
by not containing any reserved characters
## Basic Usage
### Simple URI Construction
```rust
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:
```rust
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>`][__link6] newtype wraps values that are guaranteed
to contain only URI-safe characters. This prevents common URI injection vulnerabilities:
```rust
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`][__link7] 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.
```rust
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:
```rust
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][__link8]
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`][__link9] (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`][__link10] crate types. The resulting [`Uri`][__link11] can be converted
to an [`http::Uri`][__link12] for use with HTTP clients
and servers based on [`hyper`][__link13] like [`reqwest`][__link14].
<hr/>
<sub>
This crate was developed as part of <a href="../..">The Oxidizer Project</a>. Browse this crate's <a href="https://github.com/microsoft/oxidizer/tree/main/crates/templated_uri">source code</a>.
</sub>
[__cargo_doc2readme_dependencies_info]: ggGkYW0CYXSEGy4k8ldDFPOhG2VNeXtD5nnKG6EPY6OfW5wBG8g18NOFNdxpYXKEGyftk28CR_jhG9_WxkUHtfBdG9giB010pVAzGwCsTyFCPqO3YWSCgmRodHRwZTEuNC4wgm10ZW1wbGF0ZWRfdXJpZTAuMS4x
[__link0]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=uri::Uri
[__link1]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=BaseUri
[__link10]: https://docs.rs/http/latest/http/
[__link11]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=uri::Uri
[__link12]: https://docs.rs/http/1.4.0/http/?search=Uri
[__link13]: https://docs.rs/hyper/latest/hyper/
[__link14]: https://docs.rs/reqwest/latest/reqwest/
[__link2]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=BasePath
[__link3]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=TemplatedPathAndQuery
[__link4]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=UriSafe
[__link5]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=UriSafeString
[__link6]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=UriSafe
[__link7]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=UriSafeString
[__link8]: https://datatracker.ietf.org/doc/html/rfc6570
[__link9]: https://docs.rs/templated_uri/0.1.1/templated_uri/?search=UriParam