Skip to content

Commit fce191d

Browse files
committed
Allow transforming a Context using a function, and allow a request to be initializable without source (just by callback)
1 parent 3214185 commit fce191d

File tree

3 files changed

+56
-6
lines changed

3 files changed

+56
-6
lines changed

Sources/Hummingbird/Router/RouterMethods.swift

+24-2
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,8 @@ extension RouterMethods {
7272
/// ```
7373
/// - Parameters
7474
/// - path: path prefix to add to routes inside this group
75-
/// - convertContext: Function converting context
7675
@discardableResult public func group<TargetContext>(
77-
_ path: RouterPath,
76+
_ path: RouterPath = "",
7877
context: TargetContext.Type
7978
) -> RouterGroup<TargetContext> where TargetContext.Source == Context {
8079
return RouterGroup(
@@ -83,6 +82,29 @@ extension RouterMethods {
8382
)
8483
}
8584

85+
/// Return a group inside the current group that transforms the ``RequestContext``
86+
///
87+
/// To transform the context, a function that maps between the two types is provided.
88+
/// ```
89+
/// router.group { request, oldContext -> NewContext in
90+
/// NewContext(
91+
/// coreContext: oldContext.coreContext
92+
/// )
93+
/// }
94+
/// ```
95+
/// - Parameters
96+
/// - path: path prefix to add to routes inside this group
97+
/// - mapContext: Function converting context
98+
@discardableResult public func group<TargetContext>(
99+
_ path: RouterPath = "",
100+
mapContext: @escaping @Sendable (Request, Context) async throws -> TargetContext
101+
) -> RouterGroup<TargetContext> {
102+
return RouterGroup(
103+
path: path,
104+
parent: TransformingRouterGroup(parent: self, transform: mapContext)
105+
)
106+
}
107+
86108
/// Add middleware stack to router
87109
///
88110
/// Add multiple middleware to the router using the middleware stack result builder

Sources/Hummingbird/Router/TransformingRouterGroup.swift

+20-4
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,35 @@ import HummingbirdCore
1717
import NIOCore
1818

1919
/// Internally used to transform RequestContext
20-
struct TransformingRouterGroup<InputContext: RequestContext, Context: RequestContext>: RouterMethods where Context.Source == InputContext {
20+
struct TransformingRouterGroup<InputContext: RequestContext, Context: RequestContext>: RouterMethods {
2121
typealias TransformContext = Context
2222
let parent: any RouterMethods<InputContext>
23+
let transform: @Sendable (Request, InputContext) async throws -> TransformContext
2324

2425
struct ContextTransformingResponder: HTTPResponder {
2526
typealias Context = InputContext
2627
let responder: any HTTPResponder<TransformContext>
28+
let transform: @Sendable (Request, InputContext) async throws -> TransformContext
2729

2830
func respond(to request: Request, context: InputContext) async throws -> Response {
29-
let newContext = TransformContext(source: context)
31+
let newContext = try await transform(request, context)
3032
return try await self.responder.respond(to: request, context: newContext)
3133
}
3234
}
3335

34-
init(parent: any RouterMethods<InputContext>) {
36+
init(parent: any RouterMethods<InputContext>) where Context.Source == InputContext {
3537
self.parent = parent
38+
self.transform = { _, context in
39+
TransformContext(source: context)
40+
}
41+
}
42+
43+
init(
44+
parent: any RouterMethods<InputContext>,
45+
transform: @escaping @Sendable (Request, InputContext) async throws -> TransformContext
46+
) {
47+
self.parent = parent
48+
self.transform = transform
3649
}
3750

3851
/// Add middleware (Stub function as it isn't used)
@@ -52,7 +65,10 @@ struct TransformingRouterGroup<InputContext: RequestContext, Context: RequestCon
5265
method: HTTPRequest.Method,
5366
responder: Responder
5467
) -> Self where Responder.Context == Context {
55-
let transformResponder = ContextTransformingResponder(responder: responder)
68+
let transformResponder = ContextTransformingResponder(
69+
responder: responder,
70+
transform: transform
71+
)
5672
self.parent.on(path, method: method, responder: transformResponder)
5773
return self
5874
}

Sources/Hummingbird/Server/RequestContext.swift

+12
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ public protocol RequestContext: InitializableFromSource, RequestContextSource {
7373
var responseEncoder: Encoder { get }
7474
}
7575

76+
extension Never: RequestContextSource {
77+
public var logger: Logger {
78+
fatalError("This can never be reached")
79+
}
80+
}
81+
82+
extension RequestContext where Source == Never {
83+
public init(source: Source) {
84+
fatalError("This can never be reached")
85+
}
86+
}
87+
7688
extension RequestContext {
7789
/// Logger to use with Request
7890
@inlinable

0 commit comments

Comments
 (0)