-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add interceptors interfaces #685
feat: add interceptors interfaces #685
Conversation
b92019e
to
ef8709a
Compare
Tests/ClientRuntimeTests/InterceptorTests/InterceptorTests.swift
Outdated
Show resolved
Hide resolved
Tests/ClientRuntimeTests/InterceptorTests/InterceptorTests.swift
Outdated
Show resolved
Hide resolved
27b8941
to
ee234ab
Compare
ee234ab
to
7be5f31
Compare
associatedtype AttributesType: HasAttributes | ||
|
||
/// - Returns: The input for the operation being invoked. | ||
func getInput() -> Any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the type of the input RequestType
? Not sure why this return value is untyped.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
input
and output
are the types of the modeled operation input and output, respectively. RequestType
and ResponseType
are the transport message types, like SdkHttpRequest
, HttpResponse
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the modeled input type be an associated type of this protocol like the RequestType & ResponseType then? That way you can return the actual modeled input type, and you don't need the func getInput<T>() -> T?
method below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
|
||
public func modifyBeforeTransmit(context: inout some MutableRequest<Self.RequestType, Self.AttributesType>) async throws { | ||
let input: TestInput = context.getInput()! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Force unwrapping during a test will crash the entire test suite if the unwrapped value is nil.
Instead, use XCTUnwrap
which will throw a Swift error and just fail the test being run:
let input: TestInput = try XCTUnwrap(context.getInput())
try await self.readBeforeExecution(context) | ||
} | ||
|
||
internal func modifyBeforeSerialization(context: inout InterceptorContextType) async throws { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose for making the context
param inout
in this & the other interceptor hooks?
InterceptorContextType
is a typealias for DefaultInterceptorContext
. DefaultInterceptorContext
is a class, which is a Swift reference type.
The inout
modifier means that the reference to context
can be modified by the called method to point to a different context
, which isn't what I think you want. (inout
would be necessary if the passed context was a Swift value type such as struct
and you wanted to change the struct's properties, but that is not the case here.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No purpose. Working on the orchestrator PR I realized it and just made InterceptorContext
AnyObject
, so there's no more inout
s anywhere. Need to update this PR
7be5f31
to
73fd7a7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment on using an associated type on interceptor context.
Also fix all the lint errors (mostly lines need to be broken up.)
To run swiftlint locally, in the root of the smithy-swift project on your Mac:
$ brew install swiftlint
$ swiftlint
associatedtype AttributesType: HasAttributes | ||
|
||
/// - Returns: The input for the operation being invoked. | ||
func getInput() -> Any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the modeled input type be an associated type of this protocol like the RequestType & ResponseType then? That way you can return the actual modeled input type, and you don't need the func getInput<T>() -> T?
method below.
func getAttributes() -> AttributesType | ||
} | ||
|
||
public extension InterceptorContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment above, we should make the modeled input type an associated type of InterceptorContext so this conditional cast is unneeded
Add interceptors interfaces to client libraries. Interceptors defines hooks that can be used to inject functionality into different phases of the operation execution pipeline.
Also use XCTUnwrap in tests
10c3660
to
d534cc6
Compare
Add interceptors interfaces to client libraries.
Interceptors defines hooks that can be used to inject functionality into different phases of the operation execution pipeline.
Description of changes
Interceptor
protocol, which has methods defining the hooks into the operation execution pipeline. Protocol implementations can specify concrete types for the transport request/response types (i.e.SdkHttpRequest
/HttpResponse
), as well as a type that providesAttributes
through the newHasAttributes
protocol. This allows 'less specific' interceptors that don't care about the transport request/response types, or the available attributes, to be used with more specific interceptors. See an example in InterceptorTestsHttpInterceptor
, which inherits fromInterceptor
and specializes the request, response, and attributes types to be http specific. Interceptor implementations can use this protocol so they don't have to defineRequestType
,ResponseType
, andAttributesType
if they need all http specific stuff.InterceptorContext
protocol and various child protocols that define which properties of the interceptor context can be accessed at different points in the execution pipeline. Each interceptor hook accepts one of these child protocols as input. The context protocols have the same associated types asInterceptor
, so implementations can define the types they will have in the context.HasAttributes
protocol, which is basically a protocol version of theAttributes
struct, and implements it forHttpContext
. This lets us wrapHttpContext
into interceptor context objects, and use it in interceptor implementations, much like how it is used in existing middleware.Scope
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.