This PR revamps Connect-Swift's interceptor implementation to:
Expose typed ProtobufMessage values to interceptors pre-serialization on the request path, and post-deserialization on the response path in addition to separate functions for raw data
Replace closure sets with protocols (UnaryInterceptor and StreamInterceptor) which both inherit from Interceptor and can be used to allow consumers to implement one or the other (or both) without requiring implementations for both
Provide default implementations for interceptor functions, allowing consumers to only specify functions they care about (for example, only supplying handleUnaryRequest() to mutate outbound requests without caring about responses)
The most notable changes are in UnaryInterceptor.swift and StreamInterceptor.swift. The new interceptor interfaces are:
public protocol UnaryInterceptor: Interceptor {
/// Observe and/or mutate a typed request message to be sent to the server.
///
/// Order of invocation during a request's lifecycle: 1
///
/// - parameter request: The typed request and message to be sent.
/// - parameter proceed: Closure which must be called to pass (potentially altered) request
/// to the next interceptor.
@Sendable
func handleUnaryRequest<Message: ProtobufMessage>(
_ request: HTTPRequest<Message>,
proceed: @escaping @Sendable (Result<HTTPRequest<Message>, ConnectError>) -> Void
)
/// Observe and/or mutate a raw (serialized) request to be sent to the server.
///
/// Order of invocation during a request's lifecycle: 2 (after `handleUnaryRequest()`)
///
/// - parameter request: The raw (serialized) request to be sent.
/// - parameter proceed: Closure which must be called to pass (potentially altered) request
/// to the next interceptor.
@Sendable
func handleUnaryRawRequest(
_ request: HTTPRequest<Data?>,
proceed: @escaping @Sendable (Result<HTTPRequest<Data?>, ConnectError>) -> Void
)
/// Observe and/or mutate a raw (serialized) response received from the server.
///
/// Order of invocation during a request's lifecycle: 3
///
/// - parameter response: The raw (serialized) response that was received.
/// - parameter proceed: Closure which must be called to pass (potentially altered) response
/// to the next interceptor.
@Sendable
func handleUnaryRawResponse(
_ response: HTTPResponse,
proceed: @escaping @Sendable (HTTPResponse) -> Void
)
/// Observe and/or mutate a typed (deserialized) response received from the server.
///
/// Order of invocation during a request's lifecycle: 4 (after `handleUnaryRawResponse()`)
///
/// - parameter response: The typed (deserialized) response received from the server.
/// - parameter proceed: Closure which must be called to pass (potentially altered) response
/// to the next interceptor.
@Sendable
func handleUnaryResponse<Message: ProtobufMessage>(
_ response: ResponseMessage<Message>,
proceed: @escaping @Sendable (ResponseMessage<Message>) -> Void
)
}
/// Interceptor that can observe and/or mutate streams.
public protocol StreamInterceptor: Interceptor {
/// Observe and/or mutate the creation of a stream and its associated headers.
///
/// Order of invocation during a stream's lifecycle: 1
///
/// - parameter request: The request being used to create the stream.
/// - parameter proceed: Closure which must be called to pass (potentially altered) request
/// to the next interceptor.
@Sendable
func handleStreamStart(
_ request: HTTPRequest<Void>,
proceed: @escaping @Sendable (Result<HTTPRequest<Void>, ConnectError>) -> Void
)
/// Observe and/or mutate a typed message to be sent to the server over a stream.
///
/// Order of invocation during a stream's lifecycle: 2 (after `handleStreamStart()`)
///
/// - parameter input: The message to be sent over the stream.
/// - parameter proceed: Closure which must be called to pass (potentially altered) message
/// to the next interceptor.
@Sendable
func handleStreamInput<Message: ProtobufMessage>(
_ input: Message,
proceed: @escaping @Sendable (Message) -> Void
)
/// Observe and/or mutate a message's serialized raw data to be sent to the server
/// over a stream.
///
/// Order of invocation during a stream's lifecycle: 3 (after `handleStreamInput()`)
///
/// - parameter input: The raw data to be sent over the stream.
/// - parameter proceed: Closure which must be called to pass (potentially altered) data
/// to the next interceptor.
@Sendable
func handleStreamRawInput(
_ input: Data,
proceed: @escaping @Sendable (Data) -> Void
)
/// Observe and/or mutate a raw result (such as a serialized message) received from the server
/// over a stream.
///
/// Order of invocation during a stream's lifecycle: 4
///
/// - parameter result: The raw result that was received over the stream.
/// - parameter proceed: Closure which must be called to pass (potentially altered) result
/// to the next interceptor.
@Sendable
func handleStreamRawResult(
_ result: StreamResult<Data>,
proceed: @escaping @Sendable (StreamResult<Data>) -> Void
)
/// Observe and/or mutate a typed deserialized result received from the server over a stream.
///
/// Order of invocation during a stream's lifecycle: 5 (after `handleStreamRawResult()`)
///
/// - parameter result: The deserialized result that was received over the stream.
/// - parameter proceed: Closure which must be called to pass (potentially altered) message
/// to the next interceptor.
@Sendable
func handleStreamResult<Message: ProtobufMessage>(
_ result: StreamResult<Message>,
proceed: @escaping @Sendable (StreamResult<Message>) -> Void
)
}
This PR revamps Connect-Swift's interceptor implementation to:
ProtobufMessage
values to interceptors pre-serialization on the request path, and post-deserialization on the response path in addition to separate functions for raw dataUnaryInterceptor
andStreamInterceptor
) which both inherit fromInterceptor
and can be used to allow consumers to implement one or the other (or both) without requiring implementations for bothhandleUnaryRequest()
to mutate outbound requests without caring about responses)The most notable changes are in
UnaryInterceptor.swift
andStreamInterceptor.swift
. The new interceptor interfaces are: