Skip to content

Commit 6448d6f

Browse files
committed
Make RequestContext a concrete type instead of protocol
1 parent ee3704d commit 6448d6f

9 files changed

+47
-37
lines changed

Sources/Example/Example.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ struct Example {
2323
// Using the new extension method that doesn't require type hints
2424
let privateKey = P256.Signing.PrivateKey()
2525
let server = NIOHTTPServer<HTTPServerClosureRequestHandler<
26-
HTTPServerRequestContext,
2726
HTTPRequestConcludingAsyncReader,
2827
HTTPRequestConcludingAsyncReader.Underlying,
2928
HTTPResponseConcludingAsyncWriter,
@@ -63,7 +62,6 @@ struct Example {
6362
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *)
6463
extension NIOHTTPServer
6564
where RequestHandler == HTTPServerClosureRequestHandler<
66-
HTTPServerRequestContext,
6765
HTTPRequestConcludingAsyncReader,
6866
HTTPRequestConcludingAsyncReader.Underlying,
6967
HTTPResponseConcludingAsyncWriter,
@@ -75,7 +73,6 @@ where RequestHandler == HTTPServerClosureRequestHandler<
7573
@MiddlewareChainBuilder
7674
withMiddleware middlewareBuilder: () -> some Middleware<
7775
RequestResponseMiddlewareBox<
78-
HTTPServerRequestContext,
7976
HTTPRequestConcludingAsyncReader,
8077
HTTPResponseConcludingAsyncWriter
8178
>,

Sources/Example/Middlewares/HTTPRequestLoggingMiddleware.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import Middleware
55

66
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *)
77
struct HTTPRequestLoggingMiddleware<
8-
RequestContext: HTTPRequestContext,
98
RequestConcludingAsyncReader: ConcludingAsyncReader & ~Copyable,
109
ResponseConcludingAsyncWriter: ConcludingAsyncWriter & ~Copyable
1110
>: Middleware
@@ -15,9 +14,8 @@ where
1514
ResponseConcludingAsyncWriter.Underlying.WriteElement == Span<UInt8>,
1615
ResponseConcludingAsyncWriter.FinalElement == HTTPFields?
1716
{
18-
typealias Input = RequestResponseMiddlewareBox<RequestContext, RequestConcludingAsyncReader, ResponseConcludingAsyncWriter>
17+
typealias Input = RequestResponseMiddlewareBox<RequestConcludingAsyncReader, ResponseConcludingAsyncWriter>
1918
typealias NextInput = RequestResponseMiddlewareBox<
20-
RequestContext,
2119
HTTPRequestLoggingConcludingAsyncReader<RequestConcludingAsyncReader>,
2220
HTTPResponseLoggingConcludingAsyncWriter<ResponseConcludingAsyncWriter>
2321
>

Sources/Example/Middlewares/RouteHandlerMiddleware.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import Middleware
44

55
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *)
66
struct RouteHandlerMiddleware<
7-
RequestContext: HTTPRequestContext,
87
RequestConcludingAsyncReader: ConcludingAsyncReader & ~Copyable,
98
ResponseConcludingAsyncWriter: ConcludingAsyncWriter & ~Copyable,
109
>: Middleware, Sendable
@@ -14,7 +13,7 @@ where
1413
ResponseConcludingAsyncWriter.Underlying: AsyncWriter<Span<UInt8>, any Error>,
1514
ResponseConcludingAsyncWriter.FinalElement == HTTPFields?
1615
{
17-
typealias Input = RequestResponseMiddlewareBox<RequestContext, RequestConcludingAsyncReader, ResponseConcludingAsyncWriter>
16+
typealias Input = RequestResponseMiddlewareBox<RequestConcludingAsyncReader, ResponseConcludingAsyncWriter>
1817
typealias NextInput = Never
1918

2019
func intercept(
Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,37 @@
1-
/// A protocol that defines the context for an HTTP request.
1+
/// A context object that carries additional information about an HTTP request.
22
///
3-
/// Conforming types represent contextual information that can be associated with
4-
/// an HTTP request throughout its lifecycle.
5-
public protocol HTTPRequestContext: Sendable {
3+
/// `HTTPRequestContext` provides a way to pass metadata and implementation-specific
4+
/// information through the HTTP request pipeline. This is particularly useful when
5+
/// you need to attach custom data that should be available throughout the request's
6+
/// lifecycle.
7+
///
8+
/// ## Implementation-Specific Data
9+
///
10+
/// Different server implementations can store their own specific data by conforming to the
11+
/// ``ImplementationSpecific`` protocol:
12+
///
13+
/// ```swift
14+
/// struct MyCustomContext: HTTPRequestContext.ImplementationSpecific {
15+
/// let requestID: UUID
16+
/// let startTime: Date
17+
/// }
18+
///
19+
/// var context = HTTPRequestContext()
20+
/// context.implementationSpecific = MyCustomContext(
21+
/// requestID: UUID(),
22+
/// startTime: Date()
23+
/// )
24+
/// ```
25+
public struct HTTPRequestContext: Sendable {
626

7-
}
27+
/// Conform your custom types to this protocol to store implementation-specific
28+
/// data within an ``HTTPRequestContext``.
29+
public protocol ImplementationSpecific: Sendable {}
830

9-
/// The default implementation of an ``HTTPRequestContext`` for HTTP server requests.
10-
///
11-
/// This struct provides a concrete type for representing the context of HTTP requests
12-
/// handled by a server.
13-
public struct HTTPServerRequestContext: HTTPRequestContext {
14-
/// Creates a new HTTP server request context.
15-
public init() {}
31+
/// Optional implementation-specific data associated with this request context.
32+
///
33+
/// Use this property to store custom data that is specific to your HTTP
34+
/// implementation. The stored value can be any type that conforms to
35+
/// ``ImplementationSpecific``.
36+
public var implementationSpecific: (any ImplementationSpecific)?
1637
}

Sources/HTTPServer/HTTPServerClosureRequestHandler.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ public import HTTPTypes
2525
/// ```
2626
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *)
2727
public struct HTTPServerClosureRequestHandler<
28-
RequestContext: HTTPRequestContext,
2928
ConcludingRequestReader: ConcludingAsyncReader<RequestReader, HTTPFields?> & ~Copyable,
3029
RequestReader: AsyncReader<Span<UInt8>, any Error> & ~Copyable,
3130
ConcludingResponseWriter: ConcludingAsyncWriter<RequestWriter, HTTPFields?> & ~Copyable,
@@ -35,7 +34,7 @@ public struct HTTPServerClosureRequestHandler<
3534
private let _handler:
3635
nonisolated(nonsending) @Sendable (
3736
HTTPRequest,
38-
RequestContext,
37+
HTTPRequestContext,
3938
consuming ConcludingRequestReader,
4039
consuming HTTPResponseSender<ConcludingResponseWriter>
4140
) async throws -> Void
@@ -47,7 +46,7 @@ public struct HTTPServerClosureRequestHandler<
4746
public init(
4847
handler: nonisolated(nonsending) @Sendable @escaping (
4948
HTTPRequest,
50-
RequestContext,
49+
HTTPRequestContext,
5150
consuming ConcludingRequestReader,
5251
consuming HTTPResponseSender<ConcludingResponseWriter>
5352
) async throws -> Void
@@ -61,12 +60,12 @@ public struct HTTPServerClosureRequestHandler<
6160
///
6261
/// - Parameters:
6362
/// - request: The HTTP request headers and metadata.
64-
/// - requestContext: The request's context.
63+
/// - requestContext: A ``HTTPRequestContext``.
6564
/// - requestBodyAndTrailers: A reader for accessing the request body data and trailing headers.
6665
/// - responseSender: An ``HTTPResponseSender`` to send the HTTP response.
6766
public func handle(
6867
request: HTTPRequest,
69-
requestContext: RequestContext,
68+
requestContext: HTTPRequestContext,
7069
requestBodyAndTrailers: consuming ConcludingRequestReader,
7170
responseSender: consuming HTTPResponseSender<ConcludingResponseWriter>
7271
) async throws {

Sources/HTTPServer/HTTPServerProtocol.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ public protocol HTTPServerProtocol: Sendable, ~Copyable, ~Escapable {
4545
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *)
4646
extension HTTPServerProtocol
4747
where RequestHandler == HTTPServerClosureRequestHandler<
48-
HTTPServerRequestContext,
4948
HTTPRequestConcludingAsyncReader,
5049
HTTPRequestConcludingAsyncReader.Underlying,
5150
HTTPResponseConcludingAsyncWriter,
@@ -77,7 +76,7 @@ where RequestHandler == HTTPServerClosureRequestHandler<
7776
public func serve(
7877
handler: @Sendable @escaping (
7978
_ request: HTTPRequest,
80-
_ requestContext: HTTPServerRequestContext,
79+
_ requestContext: HTTPRequestContext,
8180
_ requestBodyAndTrailers: consuming HTTPRequestConcludingAsyncReader,
8281
_ responseSender: consuming HTTPResponseSender<HTTPResponseConcludingAsyncWriter>
8382
) async throws -> Void

Sources/HTTPServer/HTTPServerRequestHandler.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ public protocol HTTPServerRequestHandler: Sendable {
7575
/// be `Span<UInt8>`.
7676
associatedtype RequestWriter: AsyncWriter<Span<UInt8>, any Error> & ~Copyable
7777

78-
associatedtype RequestContext: HTTPRequestContext
79-
8078
/// Handles an incoming HTTP request and generates a response.
8179
///
8280
/// This method is called by the HTTP server for each incoming client request. Implementations should:
@@ -89,6 +87,7 @@ public protocol HTTPServerRequestHandler: Sendable {
8987
///
9088
/// - Parameters:
9189
/// - request: The HTTP request headers and metadata.
90+
/// - requestContext: A ``HTTPRequestContext``.
9291
/// - requestBodyAndTrailers: A reader for accessing the request body data and trailing headers.
9392
/// This follows the `ConcludingAsyncReader` pattern, allowing for incremental reading of request body data
9493
/// and concluding with any trailer fields sent at the end of the request.
@@ -98,7 +97,7 @@ public protocol HTTPServerRequestHandler: Sendable {
9897
/// - Throws: Any error encountered during request processing or response generation.
9998
func handle(
10099
request: HTTPRequest,
101-
requestContext: RequestContext,
100+
requestContext: HTTPRequestContext,
102101
requestBodyAndTrailers: consuming ConcludingRequestReader,
103102
responseSender: consuming HTTPResponseSender<ConcludingResponseWriter>
104103
) async throws

Sources/HTTPServer/NIOHTTPServer.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ import Synchronization
6464
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *)
6565
public struct NIOHTTPServer<RequestHandler: HTTPServerRequestHandler>: HTTPServerProtocol
6666
where RequestHandler.ConcludingRequestReader == HTTPRequestConcludingAsyncReader,
67-
RequestHandler.ConcludingResponseWriter == HTTPResponseConcludingAsyncWriter,
68-
RequestHandler.RequestContext == HTTPServerRequestContext {
67+
RequestHandler.ConcludingResponseWriter == HTTPResponseConcludingAsyncWriter {
6968
private let logger: Logger
7069
private let configuration: HTTPServerConfiguration
7170

@@ -425,7 +424,7 @@ where RequestHandler.ConcludingRequestReader == HTTPRequestConcludingAsyncReader
425424
do {
426425
try await handler.handle(
427426
request: httpRequest,
428-
requestContext: HTTPServerRequestContext(),
427+
requestContext: HTTPRequestContext(),
429428
requestBodyAndTrailers: HTTPRequestConcludingAsyncReader(
430429
iterator: iterator,
431430
readerState: readerState

Sources/HTTPServer/RequestResponseMiddlewareBox.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ public import HTTPTypes
44
/// It is necessary to box them together so that they can be used with `Middlewares`, as this will be the `Middleware.Input`.
55
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *)
66
public struct RequestResponseMiddlewareBox<
7-
RequestContext: HTTPRequestContext,
87
RequestReader: ConcludingAsyncReader & ~Copyable,
98
ResponseWriter: ConcludingAsyncWriter & ~Copyable
109
>: ~Copyable {
1110
private let request: HTTPRequest
12-
private let requestContext: RequestContext
11+
private let requestContext: HTTPRequestContext
1312
private let requestReader: RequestReader
1413
private let responseSender: HTTPResponseSender<ResponseWriter>
1514

@@ -20,7 +19,7 @@ public struct RequestResponseMiddlewareBox<
2019
/// - responseSender: The ``HTTPResponseSender``.
2120
public init(
2221
request: HTTPRequest,
23-
requestContext: RequestContext,
22+
requestContext: HTTPRequestContext,
2423
requestReader: consuming RequestReader,
2524
responseSender: consuming HTTPResponseSender<ResponseWriter>
2625
) {
@@ -36,7 +35,7 @@ public struct RequestResponseMiddlewareBox<
3635
public consuming func withContents<T>(
3736
_ handler: nonisolated(nonsending) (
3837
HTTPRequest,
39-
RequestContext,
38+
HTTPRequestContext,
4039
consuming RequestReader,
4140
consuming HTTPResponseSender<ResponseWriter>
4241
) async throws -> T

0 commit comments

Comments
 (0)