Skip to content

Commit

Permalink
feat: add interceptor client config
Browse files Browse the repository at this point in the history
Allows configuration of interceptors on a client level by adding interceptor
providers to client config, allowing Plugins to add interceptors.

The primary addition is `InterceptorProvider`, an interface that creates
generic interceptors which can operate on any transport - http or otherwise.
When an operation is executed, interceptor providers are called to create
new instances of service-level interceptors. Creating new instances also
means we don't need to synchronize on the shared interceptors. Transport
specific config, have their own methods for adding interceptor providers, so
you can add `HttpInterceptorProvider`s to http config. Operations know which
transport they operate on, and can choose which transport-specific interceptor
providers to use.

If/when we have operation-level configuration, it might make more sense to
allow plugins to configure more generic 'operation customizations' or
something, rather than just the interceptors. Operations would then call
the customizations before executing.

A few other minor changes were made to the client libraries:
- Added actual builder methods to RequestMessageBuilder, which we would need
eventually, so I could use them in testing
- Made SdkHttpRequestBuilder final

Codegen was also updated to generate the new config methods, and to call
interceptor providers in operations to add configured interceptors.
  • Loading branch information
milesziemer committed Apr 30, 2024
1 parent 66d995a commit f269732
Show file tree
Hide file tree
Showing 109 changed files with 577 additions and 106 deletions.
5 changes: 5 additions & 0 deletions Sources/ClientRuntime/Config/DefaultClientConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,10 @@ public protocol DefaultClientConfiguration: ClientConfiguration {
/// If none is provided, only a default logger provider will be used.
var telemetryProvider: TelemetryProvider { get set }

/// Add an `InterceptorProvider` that will be used to provide interceptors for all operations.
///
/// - Parameter provider: The `InterceptorProvider` to add.
func addInterceptorProvider(_ provider: InterceptorProvider)

/// TODO(plugins): Add Checksum, etc.
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,9 @@ public protocol DefaultHttpClientConfiguration: ClientConfiguration {
///
/// Defaults to a auth scheme resolver generated based on Smithy service model.
var authSchemeResolver: ClientRuntime.AuthSchemeResolver { get set }

/// Add an `HttpInterceptorProvider` that will be used to provide interceptors for all HTTP operations.
///
/// - Parameter provider: The `HttpInterceptorProvider` to add.
func addInterceptorProvider(_ provider: HttpInterceptorProvider)
}
17 changes: 17 additions & 0 deletions Sources/ClientRuntime/Interceptor/HttpInterceptorProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

/// Provides implementations of `HttpInterceptor`.
///
/// For the generic counterpart, see `InterceptorProvider`.
public protocol HttpInterceptorProvider {

/// Creates an instance of an `HttpInterceptor` implementation.
///
/// - Returns: The `HttpInterceptor` implementation.
func create<InputType, OutputType>() -> any HttpInterceptor<InputType, OutputType>
}
25 changes: 25 additions & 0 deletions Sources/ClientRuntime/Interceptor/InterceptorProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

/// Provides implementations of `Interceptor` for any Request, Response, and Attributes types.
///
/// This can be used to create `Interceptor`s that are generic on their Request/Response/Attributes
/// types, when you don't have access to the exact types until later.
public protocol InterceptorProvider {

/// Creates an instance of an `Interceptor` implementation, specialized on the given
/// `RequestType`, `ResponseType`, and `AttributesType`.
///
/// - Returns: The `Interceptor` implementation.
func create<
InputType,
OutputType,
RequestType: RequestMessage,
ResponseType: ResponseMessage,
AttributesType: HasAttributes
>() -> any Interceptor<InputType, OutputType, RequestType, ResponseType, AttributesType>
}
7 changes: 7 additions & 0 deletions Sources/ClientRuntime/Interceptor/Interceptors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ public struct Interceptors<
self.interceptors.append(interceptor.erase())
}

/// - Parameter interceptor: The Interceptor to add.
public mutating func add(
_ interceptor: some Interceptor<InputType, OutputType, RequestType, ResponseType, AttributesType>
) {
self.interceptors.append(interceptor.erase())
}

/// - Parameter interceptorFn: The closure to use as the Interceptor hook.
public mutating func addReadBeforeExecution(
_ interceptorFn: @escaping (any BeforeSerialization<InputType, AttributesType>) async throws -> Void
Expand Down
4 changes: 4 additions & 0 deletions Sources/ClientRuntime/Message/RequestMessageBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public protocol RequestMessageBuilder<RequestType>: AnyObject {

init()

func withHost(_ host: String) -> Self

func withBody(_ body: ByteStream) -> Self

/// - Returns: The built request.
func build() -> RequestType
}
2 changes: 1 addition & 1 deletion Sources/ClientRuntime/Networking/Http/SdkHttpRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ extension SdkHttpRequestBuilder {
}
}

public class SdkHttpRequestBuilder: RequestMessageBuilder {
public final class SdkHttpRequestBuilder: RequestMessageBuilder {

required public init() {}

Expand Down
22 changes: 18 additions & 4 deletions Sources/WeatherSDK/WeatherClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,13 @@ extension WeatherClient {

public var authSchemeResolver: ClientRuntime.AuthSchemeResolver

public private(set) var interceptorProviders: [ClientRuntime.InterceptorProvider]

public private(set) var httpInterceptorProviders: [ClientRuntime.HttpInterceptorProvider]

internal let logger: ClientRuntime.LogAgent

private init(_ telemetryProvider: ClientRuntime.TelemetryProvider, _ retryStrategyOptions: ClientRuntime.RetryStrategyOptions, _ clientLogMode: ClientRuntime.ClientLogMode, _ endpoint: Swift.String?, _ idempotencyTokenGenerator: ClientRuntime.IdempotencyTokenGenerator, _ httpClientEngine: ClientRuntime.HTTPClient, _ httpClientConfiguration: ClientRuntime.HttpClientConfiguration, _ authSchemes: [ClientRuntime.AuthScheme]?, _ authSchemeResolver: ClientRuntime.AuthSchemeResolver) {
private init(_ telemetryProvider: ClientRuntime.TelemetryProvider, _ retryStrategyOptions: ClientRuntime.RetryStrategyOptions, _ clientLogMode: ClientRuntime.ClientLogMode, _ endpoint: Swift.String?, _ idempotencyTokenGenerator: ClientRuntime.IdempotencyTokenGenerator, _ httpClientEngine: ClientRuntime.HTTPClient, _ httpClientConfiguration: ClientRuntime.HttpClientConfiguration, _ authSchemes: [ClientRuntime.AuthScheme]?, _ authSchemeResolver: ClientRuntime.AuthSchemeResolver, _ interceptorProviders: [ClientRuntime.InterceptorProvider], _ httpInterceptorProviders: [ClientRuntime.HttpInterceptorProvider]) {
self.telemetryProvider = telemetryProvider
self.retryStrategyOptions = retryStrategyOptions
self.clientLogMode = clientLogMode
Expand All @@ -64,20 +68,30 @@ extension WeatherClient {
self.httpClientConfiguration = httpClientConfiguration
self.authSchemes = authSchemes
self.authSchemeResolver = authSchemeResolver
self.interceptorProviders = interceptorProviders
self.httpInterceptorProviders = httpInterceptorProviders
self.logger = telemetryProvider.loggerProvider.getLogger(name: WeatherClient.clientName)
}

public convenience init(telemetryProvider: ClientRuntime.TelemetryProvider? = nil, retryStrategyOptions: ClientRuntime.RetryStrategyOptions? = nil, clientLogMode: ClientRuntime.ClientLogMode? = nil, endpoint: Swift.String? = nil, idempotencyTokenGenerator: ClientRuntime.IdempotencyTokenGenerator? = nil, httpClientEngine: ClientRuntime.HTTPClient? = nil, httpClientConfiguration: ClientRuntime.HttpClientConfiguration? = nil, authSchemes: [ClientRuntime.AuthScheme]? = nil, authSchemeResolver: ClientRuntime.AuthSchemeResolver? = nil) throws {
self.init(telemetryProvider ?? ClientRuntime.DefaultTelemetry.provider, retryStrategyOptions ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultRetryStrategyOptions, clientLogMode ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultClientLogMode, endpoint, idempotencyTokenGenerator ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultIdempotencyTokenGenerator, httpClientEngine ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.makeClient(), httpClientConfiguration ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultHttpClientConfiguration, authSchemes, authSchemeResolver ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultAuthSchemeResolver)
public convenience init(telemetryProvider: ClientRuntime.TelemetryProvider? = nil, retryStrategyOptions: ClientRuntime.RetryStrategyOptions? = nil, clientLogMode: ClientRuntime.ClientLogMode? = nil, endpoint: Swift.String? = nil, idempotencyTokenGenerator: ClientRuntime.IdempotencyTokenGenerator? = nil, httpClientEngine: ClientRuntime.HTTPClient? = nil, httpClientConfiguration: ClientRuntime.HttpClientConfiguration? = nil, authSchemes: [ClientRuntime.AuthScheme]? = nil, authSchemeResolver: ClientRuntime.AuthSchemeResolver? = nil, interceptorProviders: [ClientRuntime.InterceptorProvider]? = nil, httpInterceptorProviders: [ClientRuntime.HttpInterceptorProvider]? = nil) throws {
self.init(telemetryProvider ?? ClientRuntime.DefaultTelemetry.provider, retryStrategyOptions ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultRetryStrategyOptions, clientLogMode ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultClientLogMode, endpoint, idempotencyTokenGenerator ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultIdempotencyTokenGenerator, httpClientEngine ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.makeClient(), httpClientConfiguration ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultHttpClientConfiguration, authSchemes, authSchemeResolver ?? DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>.defaultAuthSchemeResolver, interceptorProviders ?? [], httpInterceptorProviders ?? [])
}

public convenience required init() async throws {
try await self.init(telemetryProvider: nil, retryStrategyOptions: nil, clientLogMode: nil, endpoint: nil, idempotencyTokenGenerator: nil, httpClientEngine: nil, httpClientConfiguration: nil, authSchemes: nil, authSchemeResolver: nil)
try await self.init(telemetryProvider: nil, retryStrategyOptions: nil, clientLogMode: nil, endpoint: nil, idempotencyTokenGenerator: nil, httpClientEngine: nil, httpClientConfiguration: nil, authSchemes: nil, authSchemeResolver: nil, interceptorProviders: nil, httpInterceptorProviders: nil)
}

public var partitionID: String? {
return ""
}
public func addInterceptorProvider(_ provider: ClientRuntime.InterceptorProvider) {
self.interceptorProviders.append(provider)
}

public func addInterceptorProvider(_ provider: ClientRuntime.HttpInterceptorProvider) {
self.httpInterceptorProviders.append(provider)
}

}

public static func builder() -> ClientBuilder<WeatherClient> {
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/Baz.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import ClientRuntime

extension WeatherClientTypes {
public struct Baz: Swift.Equatable {
public struct Baz {
public var bar: Swift.String?
public var baz: Swift.String?

Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/CityCoordinates.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import ClientRuntime

extension WeatherClientTypes {
public struct CityCoordinates: Swift.Equatable {
public struct CityCoordinates {
/// This member is required.
public var latitude: Swift.Float?
/// This member is required.
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/CitySummary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import ClientRuntime

extension WeatherClientTypes {
public struct CitySummary: Swift.Equatable {
public struct CitySummary {
public var `case`: Swift.String?
/// This member is required.
public var cityId: Swift.String?
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/CreateCityInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct CreateCityInput: Swift.Equatable {
public struct CreateCityInput {
public var city: WeatherClientTypes.CitySummary?
/// This member is required.
public var coordinates: WeatherClientTypes.CityCoordinates?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct CreateCityInputBody: Swift.Equatable {
struct CreateCityInputBody {
let name: Swift.String?
let coordinates: WeatherClientTypes.CityCoordinates?
let city: WeatherClientTypes.CitySummary?
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/CreateCityOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct CreateCityOutput: Swift.Equatable {
public struct CreateCityOutput {
/// This member is required.
public var cityId: Swift.String?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct CreateCityOutputBody: Swift.Equatable {
struct CreateCityOutputBody {
let cityId: Swift.String?
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/Foo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import ClientRuntime

extension WeatherClientTypes {
public struct Foo: Swift.Equatable {
public struct Foo {
public var bar: Swift.String?
public var baz: Swift.String?

Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetCityAnnouncementsInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct GetCityAnnouncementsInput: Swift.Equatable {
public struct GetCityAnnouncementsInput {
/// This member is required.
public var cityId: Swift.String?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct GetCityAnnouncementsInputBody: Swift.Equatable {
struct GetCityAnnouncementsInputBody {
}

extension GetCityAnnouncementsInputBody: Swift.Decodable {
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetCityAnnouncementsOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct GetCityAnnouncementsOutput: Swift.Equatable {
public struct GetCityAnnouncementsOutput {
public var lastUpdated: ClientRuntime.Date?

public init(
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetCityImageInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct GetCityImageInput: Swift.Equatable {
public struct GetCityImageInput {
/// This member is required.
public var cityId: Swift.String?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct GetCityImageInputBody: Swift.Equatable {
struct GetCityImageInputBody {
}

extension GetCityImageInputBody: Swift.Decodable {
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetCityImageOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct GetCityImageOutput: Swift.Equatable {
public struct GetCityImageOutput {
/// This member is required.
public var image: ClientRuntime.ByteStream?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct GetCityImageOutputBody: Swift.Equatable {
struct GetCityImageOutputBody {
let image: ClientRuntime.ByteStream?
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetCityInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import ClientRuntime

/// The input used to get a city.
public struct GetCityInput: Swift.Equatable {
public struct GetCityInput {
/// This member is required.
public var cityId: Swift.String?

Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetCityInputBody+Decodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct GetCityInputBody: Swift.Equatable {
struct GetCityInputBody {
}

extension GetCityInputBody: Swift.Decodable {
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetCityOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct GetCityOutput: Swift.Equatable {
public struct GetCityOutput {
public var city: WeatherClientTypes.CitySummary?
/// This member is required.
public var coordinates: WeatherClientTypes.CityCoordinates?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct GetCityOutputBody: Swift.Equatable {
struct GetCityOutputBody {
let name: Swift.String?
let coordinates: WeatherClientTypes.CityCoordinates?
let city: WeatherClientTypes.CitySummary?
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetCurrentTimeInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@



public struct GetCurrentTimeInput: Swift.Equatable {
public struct GetCurrentTimeInput {

public init() { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct GetCurrentTimeInputBody: Swift.Equatable {
struct GetCurrentTimeInputBody {
}

extension GetCurrentTimeInputBody: Swift.Decodable {
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetCurrentTimeOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct GetCurrentTimeOutput: Swift.Equatable {
public struct GetCurrentTimeOutput {
/// This member is required.
public var time: ClientRuntime.Date?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct GetCurrentTimeOutputBody: Swift.Equatable {
struct GetCurrentTimeOutputBody {
let time: ClientRuntime.Date?
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetForecastInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct GetForecastInput: Swift.Equatable {
public struct GetForecastInput {
/// This member is required.
public var cityId: Swift.String?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct GetForecastInputBody: Swift.Equatable {
struct GetForecastInputBody {
}

extension GetForecastInputBody: Swift.Decodable {
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/GetForecastOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct GetForecastOutput: Swift.Equatable {
public struct GetForecastOutput {
public var chanceOfRain: Swift.Float?
public var precipitation: WeatherClientTypes.Precipitation?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

struct GetForecastOutputBody: Swift.Equatable {
struct GetForecastOutputBody {
let chanceOfRain: Swift.Float?
let precipitation: WeatherClientTypes.Precipitation?
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/WeatherSDK/models/InvokeInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ClientRuntime

public struct InvokeInput: Swift.Equatable {
public struct InvokeInput {
public var payload: ClientRuntime.Data?

public init(
Expand Down
Loading

0 comments on commit f269732

Please sign in to comment.