Swift implementation of RFC 6570: URI Template
RFC 6570 defines a simple notation for describing the structure of URIs that includes template variables. URI Templates allow for the definition of URI patterns with embedded variables to be expanded according to specific rules for each template operator.
This implementation provides:
- ✅ Full template parsing and validation
- ✅ Variable expansion (all levels 1-4)
- ✅ All eight operators (
{},{+},{#},{.},{/},{;},{?},{&}) - ✅ List and associative array support
- ✅ Modifiers (prefix
:nand explode*) - ✅ Returns RFC_3986.URI for type safety and correctness
- ✅ Swift 6 strict concurrency support
- ✅ Full Sendable conformance
- ✅ Comprehensive test coverage (89 tests, 106 RFC examples)
- ✅ RFC compliance: 95% (Grade A-)
- ✅ Convenient Swift API with Foundation URL integration
- 🚧 Template matching (reverse operation for routing) - In development
dependencies: [
.package(url: "https://github.com/swift-standards/swift-rfc-6570.git", from: "0.1.0")
]import RFC_6570
let template = try RFC_6570.Template("/users/{id}/posts")
let uri = try template.expand(variables: ["id": "123"])
// Result: RFC_3986.URI("/users/123/posts")
print(uri.value) // "/users/123/posts"For simple string-only variables, use the convenient overload:
let template = try RFC_6570.Template("/users/{id}/posts/{postId}")
let uri = try template.expand(["id": "123", "postId": "456"])
// Result: RFC_3986.URI("/users/123/posts/456")Create a Foundation URL directly using initializer extensions:
// Create URL from template string
let url = try URL(template: "https://api.example.com/users/{id}", variables: ["id": "123"])
// Result: URL("https://api.example.com/users/123")
// Or expand an existing template to URL
let template = try RFC_6570.Template("https://api.example.com/users/{id}")
let url = try URL(template: template, variables: ["id": "123"])let template = try RFC_6570.Template("/search{?q,page,limit}")
let uri = try template.expand(variables: [
"q": "swift",
"page": "1",
"limit": "50"
])
// Result: RFC_3986.URI("/search?q=swift&page=1&limit=50")Template expansion returns RFC_3986.URI for type safety:
let template = try RFC_6570.Template("/users/{id}")
let uri: RFC_3986.URI = try template.expand(["id": "123"])
// Access the URI string
print(uri.value) // "/users/123"
// URI references support relative and absolute URIs
uri.isRelative // true (no scheme)
// Convert to Foundation URL when needed
let url = try URL(template: template, variables: ["id": "123"])let template = try RFC_6570.Template("/tags/{tags*}")
let uri = try template.expand(variables: [
"tags": .list(["swift", "ios", "macos"])
])
// Result: "/tags/swift/ios/macos"let template = try RFC_6570.Template("/search{?filters*}")
let uri = try template.expand(variables: [
"filters": .dictionary(["lang": "en", "sort": "date"])
])
// Result: "/search?lang=en&sort=date"// Simple expansion
"{var}" → "value"
// Reserved expansion (allows :/?#[]@!$&'()*+,;=)
"{+var}" → "value"
// Fragment expansion
"{#var}" → "#value"
// Label expansion with dot-prefix
"{.var}" → ".value"
// Path segment expansion
"{/var}" → "/value"
// Path-style parameter expansion
"{;var}" → ";var=value"
// Query expansion
"{?var}" → "?var=value"
// Query continuation
"{&var}" → "&var=value"// Prefix modifier (limit to n characters)
let template = try Template("{var:3}")
let uri = try template.expand(variables: ["var": "value"])
// Result: "val"
// Explode modifier (expand lists/dicts separately)
let template = try Template("{?list*}")
let uri = try template.expand(variables: ["list": .list(["a", "b", "c"])])
// Result: "?list=a&list=b&list=c"This implementation conforms to RFC 6570 with the following status:
- ✅ Level 1: Simple string expansion
- ✅ Level 2: Reserved string expansion
- ✅ Level 3: Multiple operators (fragment, label, path)
- ✅ Level 4: All operators with value modifiers
- ✅ Section 2: Syntax (template parsing)
- ✅ Section 3: Expansion (all operators and modifiers)
- 🚧 Template Matching (reverse operation - not defined in RFC, custom extension)
- Template matching is heuristic-based as the RFC only defines expansion, not matching
- Some ambiguous template patterns may not match reliably without type hints
This package is under active development as part of the swift-standards project.
Apache License 2.0
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.