Skip to content

Commit 2c214e3

Browse files
committed
gardening
1 parent c32fa23 commit 2c214e3

File tree

6 files changed

+118
-112
lines changed

6 files changed

+118
-112
lines changed

FlyingFox/Sources/HTTPRequest+RouteParameter.swift

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,36 +45,7 @@ public extension HTTPRequest {
4545
}
4646

4747
/// Values extracted from the matched route and request
48-
var routeParameters: [RouteParameter] { routeParameters() }
49-
}
50-
51-
extension HTTPRequest {
52-
53-
func routeParameters(for route: HTTPRoute? = matchedRoute) -> [RouteParameter] {
54-
guard let route else { return [] }
55-
56-
let pathComponents = path
57-
.split(separator: "/", omittingEmptySubsequences: true)
58-
59-
return route.parameters
60-
.compactMap {
61-
switch $0 {
62-
case let .path(name: name, index: index):
63-
if pathComponents.indices.contains(index) {
64-
return RouteParameter(name: name, value: String(pathComponents[index]))
65-
} else {
66-
return nil
67-
}
68-
case let .query(name: name, index: index):
69-
if let value = query[index] {
70-
return RouteParameter(name: name, value: value)
71-
} else {
72-
return nil
73-
}
74-
}
75-
}
76-
}
77-
48+
var routeParameters: [RouteParameter] { Self.matchedRoute?.extractParameters(from: self) ?? [] }
7849
}
7950

8051
public extension Array where Element == HTTPRequest.RouteParameter {

FlyingFox/Sources/HTTPRequestParameter.swift

Lines changed: 0 additions & 75 deletions
This file was deleted.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//
2+
// HTTPRequestParameter.swift
3+
// FlyingFox
4+
//
5+
// Created by Simon Whitty on 11/07/2024.
6+
// Copyright © 2024 Simon Whitty. All rights reserved.
7+
//
8+
// Distributed under the permissive MIT license
9+
// Get the latest version from here:
10+
//
11+
// https://github.com/swhitty/FlyingFox
12+
//
13+
// Permission is hereby granted, free of charge, to any person obtaining a copy
14+
// of this software and associated documentation files (the "Software"), to deal
15+
// in the Software without restriction, including without limitation the rights
16+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
// copies of the Software, and to permit persons to whom the Software is
18+
// furnished to do so, subject to the following conditions:
19+
//
20+
// The above copyright notice and this permission notice shall be included in all
21+
// copies or substantial portions of the Software.
22+
//
23+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29+
// SOFTWARE.
30+
//
31+
32+
import Foundation
33+
34+
/// Converts values from `HTTPRoute.Parameter` with `HTTPRequest`
35+
public protocol HTTPRouteParameterValue {
36+
init(parameter: String) throws
37+
}
38+
39+
extension String: HTTPRouteParameterValue {
40+
public init(parameter: String) {
41+
self.init(parameter)
42+
}
43+
}
44+
45+
extension Int: HTTPRouteParameterValue {
46+
public init(parameter: String) throws {
47+
guard let value = Int(parameter)else {
48+
throw HTTPRouteParameterInvalid()
49+
}
50+
self = value
51+
}
52+
}
53+
54+
public struct HTTPRouteParameterInvalid: Error { }
55+
56+
public extension HTTPRoute {
57+
58+
func extractParameters(from request: HTTPRequest) -> [HTTPRequest.RouteParameter] {
59+
let pathComponents = request.path
60+
.split(separator: "/", omittingEmptySubsequences: true)
61+
62+
return parameters
63+
.compactMap {
64+
switch $0 {
65+
case let .path(name: name, index: index):
66+
if pathComponents.indices.contains(index) {
67+
return HTTPRequest.RouteParameter(
68+
name: name,
69+
value: String(pathComponents[index])
70+
)
71+
} else {
72+
return nil
73+
}
74+
case let .query(name: name, index: index):
75+
if let value = request.query[index] {
76+
return HTTPRequest.RouteParameter(
77+
name: name,
78+
value: value
79+
)
80+
} else {
81+
return nil
82+
}
83+
}
84+
}
85+
}
86+
}
87+
88+
#if compiler(>=5.9)
89+
extension HTTPRoute {
90+
91+
func extractParameterValues<each P: HTTPRouteParameterValue>(
92+
of type: (repeat each P).Type = (repeat each P).self,
93+
from request: HTTPRequest
94+
) throws -> (repeat each P) {
95+
let parameters = extractParameters(from: request).map(\.value)
96+
var idx = 0
97+
return try (repeat getParameter(at: &idx, parameters: parameters, type: (each P).self))
98+
}
99+
100+
private func getParameter<P: HTTPRouteParameterValue>(at index: inout Int, parameters: [String], type: P.Type) throws -> P {
101+
defer { index += 1 }
102+
103+
guard parameters.indices.contains(index) else {
104+
throw HTTPRouteParameterInvalid()
105+
}
106+
107+
return try P(parameter: parameters[index])
108+
}
109+
}
110+
#endif

FlyingFox/Sources/HTTPServer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public final actor HTTPServer {
6969
}
7070

7171
#if compiler(>=5.9)
72-
public func appendRoute<each P: HTTPRequestParameter>(
72+
public func appendRoute<each P: HTTPRouteParameterValue>(
7373
_ route: HTTPRoute,
7474
handler: @Sendable @escaping (repeat each P) async throws -> HTTPResponse
7575
) {

FlyingFox/Sources/Handlers/RoutedHTTPHandler.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ public struct RoutedHTTPHandler: HTTPHandler, Sendable {
4545
}
4646

4747
#if compiler(>=5.9)
48-
public mutating func appendRoute<each P: HTTPRequestParameter>(
48+
public mutating func appendRoute<each P: HTTPRouteParameterValue>(
4949
_ route: HTTPRoute,
5050
handler: @Sendable @escaping (repeat each P) async throws -> HTTPResponse
5151
) {
5252
let closure = ClosureHTTPHandler { request in
53-
let params = try request.extractParameters(type: (repeat each P).self)
53+
let params = try route.extractParameterValues(of: (repeat each P).self, from: request)
5454
return try await handler(repeat each params)
5555
}
5656
append((route, closure))

FlyingFox/Tests/HTTPRouteTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -478,19 +478,19 @@ final class HTTPRouteTests: XCTestCase {
478478
let request = HTTPRequest.make(path: "/mock/12/hello/fish")
479479

480480
XCTAssertTrue(
481-
try request.extractParameters(for: route) == (12, "fish")
481+
try route.extractParameterValues(from: request) == (12, "fish")
482482
)
483483

484484
XCTAssertTrue(
485-
try request.extractParameters(for: route) == (12)
485+
try route.extractParameterValues(from: request) == (12)
486486
)
487487

488488
XCTAssertThrowsError(
489-
try request.extractParameters(for: route, type: (Int, Int).self)
489+
try route.extractParameterValues(of: (Int, Int).self, from: request)
490490
)
491491

492492
XCTAssertThrowsError(
493-
try request.extractParameters(for: route, type: (Int, String, String).self)
493+
try route.extractParameterValues(of: (Int, String, String).self, from: request)
494494
)
495495
}
496496
#endif

0 commit comments

Comments
 (0)