npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nest-aws-sdk

v3.1.0

Published

A thin wrapping layer around the aws-sdk package for clean NestJS dependency injection.

Downloads

51,562

Readme

Features

  • Decorator for injecting AWS services.
  • An AWS service factory for on-the-fly AWS client creation.
  • A simple dependency injection model with AwsSdkModule.forRootAsync() and AwsSdkModule.forFeature().
  • Helper test tools for creating mocked AWS clients.

How To Use

Install

npm install --save nest-aws-sdk aws-sdk

Basic Usage - Root-level feature registration

Below is an example of injecting the AwsSdkModule at the global root level. This also demonstrates some of the testing tools provided to make mocking and spying on AWS clients easier.

// app.module.ts
import { Module } from '@nestjs/common';
import { AwsSdkModule } from 'nest-aws-sdk';
import { SharedIniFileCredentials, S3 } from 'aws-sdk';
import { ServiceConfigurationOptions } from 'aws-sdk/lib/service';
import { S3ManagerModule } from './s3-manager/s3-manager.module';

@Module({
  imports: [
    S3ManagerModule,
    AwsSdkModule.forRoot({
      defaultServiceOptions: {
        region: 'us-east-1',
        credentials: new SharedIniFileCredentials({
          profile: 'my-profile',
        }),
      },
      services: [S3],
    }),
  ],
  providers: [],
  exports: [],
})
export class AppModule {}
// s3-manager.module.ts
import { Module } from '@nestjs/common';
import { S3ManagerService } from './s3-manager.service';

@Module({
  imports: [],
  providers: [S3ManagerService],
  exports: [S3ManagerService],
})
class S3ManagerModule {}
// s3-manager.service.ts
import { Injectable } from '@nestjs/common';
import { InjectAwsService } from 'nest-aws-sdk';
import { S3 } from 'aws-sdk';

@Injectable()
export class S3ManagerService {
  constructor(@InjectAwsService(S3) private readonly s3: S3) {}

  async listBucketContents(bucket: string) {
    const response = await this.s3.listObjectsV2({ Bucket: bucket }).promise();
    return response.Contents.map(c => c.Key);
  }
}
// s3-manager.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { S3 } from 'aws-sdk';
import {
  createAwsServiceMock,
  createAwsServicePromisableSpy,
  getAwsServiceMock,
} from 'nest-aws-sdk/dist/testing';
import { S3ManagerService } from './s3-manager.service';

describe('S3ManagerService', () => {
  describe('listBucketContents()', () => {
    it('should call the list method and return the Content keys', async () => {
      const module: TestingModule = await Test.createTestingModule({
        providers: [
          S3ManagerService,
          createAwsServiceMock(S3, {
            useValue: {
              listObjectsV2: () => null,
            },
          }),
        ],
      }).compile();

      const service = module.get(S3ManagerService);

      const listSpy = createAwsServicePromisableSpy(
        getAwsServiceMock(module, S3),
        'listObjectsV2',
        'resolve',
        {
          Contents: [{ Key: 'myKey' }],
        },
      );

      const result = await service.listBucketContents('myBucket');

      expect(result.length).toBe(1);
      expect(result[0]).toBe('myKey');
      expect(listSpy).toHaveBeenCalledTimes(1);
      expect(listSpy).toHaveBeenCalledWith({ Bucket: 'myBucket' });
    });
  });
});

Basic Usage - Module-level feature registration

Below is an example of injecting the AwsSdkModule global providers at the root-level and the client feature registration at the feature-submodule.

// app.module.ts
import { Module } from '@nestjs/common';
import { AwsSdkModule } from 'nest-aws-sdk';
import { SharedIniFileCredentials } from 'aws-sdk';
import { ServiceConfigurationOptions } from 'aws-sdk/lib/service';
import { S3ManagerModule } from './s3-manager/s3-manager.module';

@Module({
  imports: [
    S3ManagerModule,
    AwsSdkModule.forRootAsync({
      defaultServiceOptions: {
        useValue: {
          region: 'us-east-1',
          credentials: new SharedIniFileCredentials({
            profile: 'my-profile',
          }),
        },
      },
    }),
  ],
  providers: [],
  exports: [],
})
export class AppModule {}
// s3-manager.module.ts
import { Module } from '@nestjs/common';
import { AwsSdkModule } from 'nest-aws-sdk';
import { S3 } from 'aws-sdk';
import { S3ManagerService } from './s3-manager.service';

@Module({
  imports: [AwsSdkModule.forFeatures([S3])],
  providers: [S3ManagerService],
  exports: [S3ManagerService],
})
class S3ManagerModule {}

AwsSdkModule.forRoot()

AwsSdkModule.forRoot() is the simplest form of registration and uses statically assigned options values.

options

defaultServiceOptions?: Partial | (() => Partial);

defaultServiceOptions is an optional object or object-returning method to get the aws-sdk ServiceConfigurationOptions object. This includes the region, credentials, and other client-level configuration.

services?: Array<AwsServiceType | AwsServiceWithServiceOptions>,

services can optionally be registered at the root level by passing an array of aws-sdk types, i.e. S3, or a AwsServiceWithServiceOptions object. These are interchangable and can be used as such:

import { AwsSdkModule } from 'nest-aws-sdk';
import { CloudFront, S3, SharedIniFileCredentials } from 'aws-sdk';

@Module({
  imports: [
    AwsSdkModule.forRoot({
      services: [
        S3,
        {
          service: CloudFront,
          serviceOptions: {
            credentials: new SharedIniFileCredentials({
              profile: 'aws-nest-sdk',
            }),
          },
        },
      ],
    }),
  ],
})
class AppRootModule {}

Note: the supplied values in serviceOptions will override the values supplied in the defaultServiceOptions object.

forRootAsync

AwsSdkModule.forRootAsync() is an injectable form of the AwsSdkModule.forRoot() import and currently supports two types of instantiation: 'useFactory' and 'useValue'. Support for ClassProvider and ExistingProvider coming soon.

No parameters

AwsSdkModule.forRootAsync() can be called with no provided parameters. This will allow the AWS clients to be created without any provided credential context, which is not uncommon when running in an AWS environment.

// app.module.ts
import { Module } from '@nestjs/common';
import { AwsSdkModule } from 'nest-aws-sdk';
import { S3ManagerModule } from './s3-manager/s3-manager.module';

@Module({
  imports: [S3ManagerModule, AwsSdkModule.forRootAsync()],
  providers: [],
  exports: [],
})
export class AppModule {}

useValue

useValue is the simplest way to modify the service options of the created clients.

// app.module.ts
import { Module } from '@nestjs/common';
import { AwsSdkModule } from 'nest-aws-sdk';
import { SharedIniFileCredentials } from 'aws-sdk';
import { ServiceConfigurationOptions } from 'aws-sdk/lib/service';
import { S3ManagerModule } from './s3-manager/s3-manager.module';

@Module({
  imports: [
    S3ManagerModule,
    AwsSdkModule.forRootAsync({
      defaultServiceOptions: {
        useValue: {
          region: 'us-east-1',
          credentials: new SharedIniFileCredentials({
            profile: 'my-profile',
          }),
        },
      },
    }),
  ],
  providers: [],
  exports: [],
})
export class AppModule {}

useFactory

useFactory allows for dynamic modification of the service options. This includes support for imports and inject.

// app.module.ts
import { Module } from '@nestjs/common';
import { AwsSdkModule } from 'nest-aws-sdk';
import { ConfigService, ConfigModule } from './config';

@Module({
  imports: [
    AwsSdkModule.forRootAsync({
      defaultServiceOptions: {
        useFactory: (cs: ConfigService) => {
          return {
            region: 'us-east-1',
            credentials: cs.getCredentials(),
          };
        },
        imports: [ConfigModule],
        inject: [ConfigService],
      },
    }),
  ],
  providers: [],
  exports: [],
})

AwsSdkModule.forFeatures()

AwsSdkModule.forFeatures() creates the providers for the AWS clients you wish to use at a module-specific level.

Note: forFeatures cannot be used in combination with root-level service registrations.

Basic usage

To provide clients to the module context, pass the client constructor symbol to the AwsSdkModule.forFeatures() method. Note, it is best to import the client directly from aws-sdk instead of from deeper paths - the deeper paths may produce unexpected behaviors.

import { Module } from '@nestjs/common';
import { S3 } from 'aws-sdk';
import { AwsSdkModule } from 'nest-aws-sdk';

@Module({
  imports: [AwsSdkModule.forFeatures([S3])],
  providers: [],
  exports: [],
})
class AppSubModule {}

AwsServiceFactory

The AwsServiceFactory class is exposed to the root- and feature-level. This allows for dynamic creation of AWS clients without feature registration. In addition, the default options are injectable via the @InjectAwsDefaultOptions() decorator.

import { Injectable } from '@nestjs/common';
import { InjectAwsDefaultOptions } from '../src';
import { S3, SharedIniFileCredentials } from 'aws-sdk';
import { ServiceConfigurationOptions } from 'aws-sdk/lib/service';

@Injectable()
export class AppService {
  constructor(
    @InjectAwsDefaultOptions() readonly options: ServiceConfigurationOptions,
    readonly factory: AwsServiceFactory,
  ) {}
}

Testing

For testing AWS clients, we recommend fully replacing the AWS clients as they have side-effects inside of the constructor. To do so, methods are made available to make mocking these clients very simple.

createAwsServiceMock

This method allows for override an AWS client instantiation. To mock a client, call the createAwsServiceMock method with the client constructor and pass a provider object that will be used in its stead.

const module: TestingModule = await Test.createTestingModule({
  providers: [
    S3ManagerService,
    createAwsServiceMock(S3, {
      useValue: {
        listObjectsV2: () => null,
      },
    }),
  ],
}).compile();

getAwsServiceMock

To retrieve a mock from the test bed via the correct symbol, getAwsServiceMock is exported.

const s3 = getAwsServiceMock(module, S3);

createAwsServicePromisableSpy

It is common to want to use the .promise() method returned by most AWS client methods. To make spying on these simpler, the createAwsServicePromisableSpy creates a spy and returns a promised value.

it('should call the list method and return the Content keys', async () => {
  const listSpy: jest.SpyInstance = createAwsServicePromisableSpy(
    s3, // the mocked object to spy on
    'listObjectsV2', // the method to spy on
    'resolve', // 'resolve' or 'reject'
    { Contents: [{ Key: 'myKey' }] }, // the value to resolve or reject
  );

  const result = await service.listBucketContents('myBucket');

  expect(result.length).toBe(1);
  expect(result[0]).toBe('myKey');
  expect(listSpy).toHaveBeenCalledTimes(1);
  expect(listSpy).toHaveBeenCalledWith({ Bucket: 'myBucket' });
});

Stay In Touch

License

nest-aws-sdk is MIT licensed.

Contributing

Nest-AWS-SDK is released through semantic-release. Effectively this means that versioning is based off commit messages. Please review angular-changelog-convention and commit under that format. Otherwise semantic-release won't pick up commits for versioning this library.