diff --git a/Sources/URLRouting/Client/Client.swift b/Sources/URLRouting/Client/Client.swift index 7311545ddf..97c3b959a6 100644 --- a/Sources/URLRouting/Client/Client.swift +++ b/Sources/URLRouting/Client/Client.swift @@ -41,6 +41,20 @@ public struct URLRoutingClient<Route> { throw URLRoutingDecodingError(bytes: data, response: response, underlyingError: error) } } + + /// Allows you to create a client that only handles a subset of routes. + /// + /// - Parameters: + /// - toRoute: A closure that converts `ChildRoute` back to `Route`. + /// + /// - Returns: A client that can only request child routes. + public func scoped<ChildRoute>( + to toRoute: @escaping (ChildRoute) -> Route + ) -> URLRoutingClient<ChildRoute> { + .init { child in + try await self.request(toRoute(child)) + } + } } public struct URLRoutingDecodingError: Error { diff --git a/Tests/URLRoutingTests/ClientTests.swift b/Tests/URLRoutingTests/ClientTests.swift new file mode 100644 index 0000000000..09d52287c2 --- /dev/null +++ b/Tests/URLRoutingTests/ClientTests.swift @@ -0,0 +1,58 @@ +import Parsing +import URLRouting +import XCTest + +#if canImport(FoundationNetworking) +import FoundationNetworking +#endif + +class ClientTests: XCTestCase { + enum TestRoute: Equatable { + case one + case child(ChildRoute) + } + + enum ChildRoute: Equatable { + case one + case two + } + + static let router = OneOf { + Route(.case(TestRoute.one)) { + Path { "one" } + } + Route(.case(TestRoute.child)) { + Path { "child" } + OneOf { + Route(.case(ChildRoute.one)) { + Path { "one" } + } + Route(.case(ChildRoute.two)) { + Path { "two" } + } + } + } + } + + func testBasics() async throws { + let client = URLRoutingClient<TestRoute>.failing + .override(.one) { try .ok("result") } + + let (value, response) = try await client.request(.one, as: String.self) + + XCTAssertEqual("result", value) + XCTAssertEqual(200, (response as! HTTPURLResponse).statusCode) + } + + func testScoped() async throws { + let client = URLRoutingClient<TestRoute>.failing + .override(.child(.one)) { try .ok("result") } + + let scopedClient = client.scoped(to: TestRoute.child) + + let (value, response) = try await scopedClient.request(.one, as: String.self) + + XCTAssertEqual("result", value) + XCTAssertEqual(200, (response as! HTTPURLResponse).statusCode) + } +}