SmokeAWSGenerate primarily provides a code generator that will generate a Swift client package using an Open API/Swagger model for endpoints hosted by AWS API Gateway.
By default, the generator will create two targets in the Swift client package, a Model target and a Client target.
- The model target will create Swift types and enumerations for the objects specified in the model
- The client target will create
- a Swift protocol based on the model operations.
- an API Gateway client implementation that conforms to the protocol.
- a Mock implementation that conforms to the protocol with optional overrides for each API. By default returns a default instance of each APIs return type.
- a Throwing Mock implementation that conforms to the protocol with optional overrides for each API. By default throws a specified error.
- a Configuration type that can used to share client configuration between clients.
- an Operations client that can be used to share the underlying http client between clients.
This might be a Github repository or some other repository. Check out this location so you can add files to it.
Depending on your use case, this model can either be hosted with the same Swift package as the Swift client or in a separate package.
For models in the same Swift package, just go ahead and create the model according to the Open API spec or Swagger spec. Typically this model will be in the root directory of the Client package.
If the model is hosted in a separate Swift Package, the model file will need to be specified as a resource of that package. The following shows the minimal Swift Package manifest that is required for a model package.
// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "ServiceModel",
products: [
.library(
name: "ServiceModel",
targets: ["ServiceModel"]),
],
targets: [
.target(
name: "ServiceModel",
dependencies: [],
path: "api",
resources: [.copy("OpenAPI30.yaml")]),
]
)
This model package can have other products and targets if required. If your model package has only your model file (for example if you want to share your model across your service and client packages independently of anything else), you will need to add an empty Swift file in the base directory of the target (in this case /api) due to a current limitation of SwiftPM.
Then go ahead and create the model according to the Open API spec or Swagger spec.
Clone this repository (smoke-aws-generate) and from its base directory, run the following command, replacing values as appropriate.
This command will generate the package manifest and other scaffolding required to build the client package.
swift run APIGatewayClientInitialize -c release --base-file-path <path-to-the-client-package> \
--base-name "PersistenceExample" \
--model-format "OPENAPI3_0" \
--model-path "OpenAPI30.yaml"
swift run APIGatewayClientInitialize -c release --base-file-path <path-to-the-client-package> \
--base-name "PersistenceExample" \
--model-format "OPENAPI3_0" \
--model-path "OpenAPI30.yaml" \
--model-product-dependency "ServiceModel" \
--package-location "https://github.com/example/service-model.git" \
--version-requirement-type "from"
--version-requirement "1.0.0"
Note: SWAGGER
must be used for the --model-format
parameter when using Swagger 2.0 model files.
Note: You can optionally specify a --model-target-dependency
parameter if the target where the
model file is hosted is not the same as the product name.
You can also optionally specify --model-target-name
and --client-target-name
parameters to specify custom
target names. Otherwise \(base-name)Model
and \(base-name)Client
will be used.
Note: You can also manually generate a Swift package manifest and structure along with the configuration file (see next step).
The APIGatewayClientInitialize
executable is simply a convenience and not required to build the client package.
As part of the previous step, a configuration file called api-gateway-client-swift-codegen.json
will have been generated in the base directory of the client package. This file stores configuration
options for the build-time code generation.
{
"baseName" : "PersistenceExample",
"modelFormat" : "OPENAPI3_0",
"modelLocations" : {
"default" : {
"modelFilePath" : "OpenAPI30.yaml",
"modelProductDependency" : "ServiceModel"
}
}
}
You can add the following additional options to this configuration file-
- modelFormat: The expected format of the model file. Optional; defaulting to
OPENAPI3_0
.SWAGGER
can also be specified. - modelOverride: A set of overrides to apply to the model. Optional.
- httpClientConfiguration: Configuration for the generated http service clients. Optional.
- shapeProtocols:
ENABLED
will conform model types to shape protocols that allow for easy conversion between different models. Optional; defaulting toDISABLED
. - eventLoopFutureClientAPIs:
ENABLED
will generate EventLoopFuture-returning client APIs. Mock and Throwing Mock will require an EventLoop passed to their initializer. Optional; defaulting toDISABLED
. - minimumCompilerSupport:
UNKNOWN
will generate a client that supports Swift 5.5 and 5.4. Optional; defaulting to5.6
. - clientConfigurationType:
GENERATOR
will generate a legacy client generator type instead of the configuration and operations clients types. Optional; defaulting toCONFIGURATION_OBJECT
. - modelTargets: Provides the ability to customise the model target used by a client target. Optional, if not specified ``(baseName)Model` will be used.
The schemas for the modelOverride
and httpClientConfiguration
fields can be found here - https://github.com/amzn/service-model-swift-code-generate/blob/main/Sources/ServiceModelEntities/ModelOverride.swift.
An example configuration - including modelOverride
configuration - can be found here - https://github.com/amzn/smoke-framework-examples/blob/612fd9dca5d8417d2293a203aca4b02672889d12/PersistenceExampleService/smoke-framework-codegen.json.
Shape protocols allow you to convert between similar types in different models
extension Model1.Location: Model2.LocationShape {}
let model2Location = model1.asModel2Location()
The modelTargets
option can be specified as shown below.
{
"baseName" : "PersistenceExample",
"modelFormat" : "OPENAPI3_0",
"modelLocations" : {
"default" : {
"modelFilePath" : "OpenAPI30.yaml",
"modelProductDependency" : "ServiceModel"
}
},
"modelTargets": {
"MyClientTarget": {
"modelTargetName": "MyModelTarget"
}
}
}
You can now use the client package from other Swift packages by depending on the Client target.
The easiest way to use the client is to initialize it directly and then at some later point shut it down.
let client = APIGatewayPersistenceExampleClient(credentialsProvider: credentialsProvider,
awsRegion: awsRegion,
endpointHostName: endpointHostName)
...
// Use the client
...
try await client.shutdown()
Credential Providers need to conform to the CredentialsProvider protocol from SmokeAWSCore. Smoke AWS Credentials provides implementations for obtaining or assuming short-lived rotating AWS IAM credentials.
The client initializer can also optionally accept logger
, timeoutConfiguration
, connectionPoolConfiguration
,
retryConfiguration
, eventLoopProvider
and reportingConfiguration
.
For use cases where you want to reuse the underlying HTTP client between instances, you can use the operations client type (or similarly the configuration object type to share client configuration but not the underlying HTTP client).
// Start of application
let operationsClient = APIGatewayPersistenceExampleOperationsClient(credentialsProvider: credentialsProvider,
awsRegion: awsRegion,
endpointHostName: endpointHostName)
// Per-request
let client = APIGatewayPersistenceExampleClient(operationsClient: operationsClient,
logger: logger)
// Use the client within the request
// This client doesn't need to be explicitly shutdown
// as it doesn't own the underlying http client
// client.shutdown() would be a no-op
// End of application
try await operationsClient.shutdown()
You can use the Mock and Throwing Mock client implementations for unit testing. These implementations conform to the generated client protocol. Using this protocol within application code will allow you to test using a mock client and use the API Gateway client for actual usage.
Each client API can be overridden with any logic required for a unit test.
func testCodeThatUsesGetCustomerDetails() {
func getCustomerDetails(input: PersistenceExampleModel.GetCustomerDetailsRequest) async throws
-> PersistenceExampleModel.CustomerAttributes {
// mock behaviour of the API
}
let mockClient = MockPersistenceExampleClient(getCustomerDetails: getCustomerDetails)
// run a test using the mock client
Each client also provides a set of convenience initializers using the HTTPClientInvocationAttributes
protocol to pass
the Logger
, EventLoop
, InternalRequestId
and a metrics aggregator associated with the current request/invocation.
For example, when using the smoke-framework
, you can directly pass the provided SmokeServerInvocationReporting
instance
into the initializer of the client.
public func getInvocationContext(
invocationReporting: SmokeServerInvocationReporting<SmokeInvocationTraceContext>) -> TheServiceContext {
let theClient = APIGatewayAnotherServiceClient(operationsClient: self.theOperationsClient, invocationAttributes: invocationReporting)
...
return TheServiceContext(...
theClient: theClient,
...)
}
If you want the client to ignore the EventLoop
provided by the HTTPClientInvocationAttributes
instance, you can
set ignoreInvocationEventLoop
on the configuration object or operations client to true
. Otherwise, the client will
attempt to execute the client http requests on the same event loop as the provided invocation.
The SmokeAWSGenerate
executable is a code generator for the SmokeAWS library.
Clone the SmokeAWS repository to your local machine.
Clone this repository to your local machine.
From within your checked out copy of this repository, run this command-
swift run -c release SmokeAWSGenerate \
--base-file-path <path_to_the_smoke_aws_repository>
This library is licensed under the Apache 2.0 License.