modern-swift-dev/pathways-swift
Pathways is a small, dependency-free Swift package for defining typed deep-link paths, converting those paths to and from Codable values, and dispatching incoming URLs to main-actor handlers.
Features
- Strongly typed URL path parameters through Swift
Codable - Encoding models into percent-escaped URL paths
- Decoding URL paths into application-defined models
- Typed and path-only routing handlers
- Optional exact-host filtering
- Query parameter delivery to handlers
- Experimental fragment-route and fragment-parameter support
- Swift 6 concurrency annotations and main-actor handler execution
- No third-party runtime dependencies
Requirements
- Swift 6.0 or newer
- macOS 15 or newer
- iOS 18 or newer
- tvOS 18 or newer
- watchOS 10 or newer
- visionOS 1 or newer
Installation
In Xcode, use File > Add Package Dependencies and enter:
https://github.com/modern-swift-dev/pathways-swift.gitOr add the package in Package.swift:
dependencies: [
.package(
url: "https://github.com/modern-swift-dev/pathways-swift.git",
from: "1.0.0"
)
]Add Pathways to the target that uses it:
.target(
name: "YourTarget",
dependencies: [
.product(name: "Pathways", package: "pathways-swift")
]
)Quick start
1. Define a route
Adopt Pathway and declare a path pattern. Placeholder names begin with : and correspond to Codable keys.
import Pathways
struct ProductRoute: Pathway {
static let pattern = "/products/:productID"
let productID: Int
}2. Encode and decode
import Foundation
import Pathways
let path = try PathwayEncoder.shared.encode(ProductRoute(productID: 42))
// /products/42
let url = URL(string: "https://example.com/products/42")!
let route = try PathwayDecoder.shared.decode(ProductRoute.self, from: url)
// route.productID == 423. Register a handler
var router = Pathways()
router.register(host: "example.com", ProductRoute.self) { route, query in
navigateToProduct(id: route.productID, campaign: query["campaign"])
}
let handled = try router.handle(url)The handler executes on the main actor. handle(_:) returns false when no route matches and throws when a matched typed route cannot be decoded.
Route patterns
Patterns contain literal path components and named placeholders:
/teams/:teamID/members/:memberIDThe model stays flat and each placeholder maps to a Codable key:
struct MemberRoute: Pathway {
static let pattern = "/teams/:team_id/members/:member_id"
let teamID: Int
let memberID: UUID
enum CodingKeys: String, CodingKey {
case teamID = "team_id"
case memberID = "member_id"
}
}Supported scalar values include strings, booleans, integer and floating-point types, raw-value Codable enums, UUIDs, and ISO 8601 dates. Nested values and collections are not supported.
Path-only routing
Register a path directly when no typed path values are needed:
router.register(host: "example.com", path: "/settings") { query in
navigateToSettings(tab: query["tab"])
}Path-only registrations use prefix matching by default, so /settings also matches /settings/privacy. Pass matching: .exact when the complete normalized path must match:
router.register(host: "example.com", path: "/settings", matching: .exact) { query in
navigateToSettings(tab: query["tab"])
}Exact matching also applies to typed routes. Each : placeholder matches one non-empty path component.
Query and fragment parameters
Handler dictionaries contain standard query parameters by default. For URLs that encode a route and parameters in the fragment, opt in per registration:
router.register(
host: "example.com",
path: "/callback/#complete",
supportFragmentParams: true
) { parameters in
completeSignIn(token: parameters["token"])
}This supports a URL such as https://example.com/callback#complete?token=abc. Fragment handling is experimental.
Examples
The Examples directory contains standalone packages:
- CodableRoutes demonstrates model encoding and decoding.
- RoutingCenter demonstrates host-aware dispatch and query parameters.
Each can be run independently with swift run from its directory.
Documentation
Contributing
Guides and examples live in Documentation/Site. The central documentation repository owns the shared Astro theme, builds the guides and DocC API reference, and publishes them daily. For local builds and previews, follow the docs README.
See CONTRIBUTING.md for development and maintenance instructions.
License
Pathways is available under the MIT License. See LICENSE.
Package Metadata
Repository: modern-swift-dev/pathways-swift
Default branch: main
README: README.md