Create a SDK Client Factory
Introduction
Most Resource Actions will want to interface with appropriate cloud SDKs to manipulate cloud resources. Before you can use the SDK clients, you will need to instantiate the client.
A Container factory is the recommended way to instantiate SDK clients. This enables you to maintain a singleton set of clients, reference these clients using Octo Container class, and can be easily mocked for testing.
Usage
Create a Factory
In this example, we are creating a factory for an AWS EC2 client from the AWS SDK V3 JavaScript library. We recommend reading the official AWS SDK V3 JavaScript documentation on how to instantiate these clients.
import { EC2Client } from '@aws-sdk/client-ec2';
import { Factory } from '@quadnix/octo';
import type { EndpointInputConfig } from '@smithy/middleware-endpoint/dist-types/resolveEndpointConfig.js';
import type { AwsCredentialIdentityProvider } from '@smithy/types';
@Factory<EC2Client>(EC2Client, { metadata: { package: '@example' } })
export class EC2ClientFactory {
private static instance: EC2Client;
static async create(
awsRegionId: string,
credentials: AwsCredentialIdentityProvider,
endpointInputConfig: EndpointInputConfig = {},
): Promise<EC2Client> {
if (!this.instance) {
this.instance = new EC2Client({ ...credentials, ...endpointInputConfig, region: awsRegionId });
}
return this.instance;
}
}
The above factory is a singleton, and will always return the same instance on every call.
To return new instances on every call, you can modify the factory to not be singleton.
Using the Factory
Once you have created the factory, you can use it to get the client instance.
import { EC2Client } from '@aws-sdk/client-ec2';
import { fromIni } from '@aws-sdk/credential-providers';
import { Container } from '@quadnix/octo';
import { EC2ClientFactory } from './factories/ec2-client.factory.js';
const container = Container.getInstance();
const ec2Client = await container.get<EC2Client, typeof EC2ClientFactory>(EC2Client, {
args: ['us-east-1', fromIni({ profile: 'default' })],
metadata: { package: '@example' },
});
Notice, how the arguments of create() method are passed in the args,
and metadata allows you to target your factory out of any other EC2Client factories that exist.
This is why setting a package scope (e.g. @example) is so important.
Octo Factories
Follow the links for a more
advanced usage
example of how octo-aws-cdk package creates its factories.
Octo uses the Account
modules to predefine
AwsCredentialIdentityProvider so that actions don't have to always
pass a credential provider.
container.registerValue('AwsCredentialIdentityProvider', credentials, {
metadata: { awsAccountId: inputs.accountId, package: '@octo' },
});
It also defines a common create() method for all its AWS SDK factories to provide a consistent interface to
all the actions.
It maintains a static set of instances per AWS account, and per region.
For a more detailed explanation, refer to the source code and its class comments.