A progressive Node.js framework for building efficient and scalable server-side applications.
$ npm install --save nestjs-dynamoose dynamoose
A AWS NestJS Starter project has been created to demo the usage of this library.
1. Add import into your app module
src/app.module.ts
import { DynamooseModule } from 'nestjs-dynamoose';
import { UserModule } from './user/user.module';
@Module({
imports: [
DynamooseModule.forRoot(),
UserModule,
],
})
export class AppModule {
forRoot()
optionally accepts the following options defined by DynamooseModuleOptions
:
interface DynamooseModuleOptions {
aws?: {
accessKeyId?: string;
secretAccessKey?: string;
region?: string;
};
local?: boolean | string;
ddb?: DynamoDB;
table?: TableOptionsOptional;
logger?: boolean | LoggerService;
}
There is also forRootAsync(options: DynamooseModuleAsyncOptions)
if you want to use a factory with dependency injection.
2. Create a schema
src/user/user.schema.ts
import { Schema } from 'dynamoose';
export const UserSchema = new Schema({
id: {
type: String,
hashKey: true,
},
name: {
type: String,
},
email: {
type: String,
},
});
src/user/user.interface.ts
export interface UserKey {
id: string;
}
export interface User extends UserKey {
name: string;
email?: string;
}
UserKey
holds the hashKey/partition key and (optionally) the rangeKey/sort key. User
holds all attributes of the document/item. When creating this two interfaces and using when injecting your model you will have typechecking when using operations like Model.update()
.
3. Add the models you want to inject to your modules
This can be a feature module (as shown below) or within the root AppModule next to DynamooseModule.forRoot()
.
src/user/user.module.ts
import { DynamooseModule } from 'nestjs-dynamoose';
import { UserSchema } from './user.schema';
import { UserService } from './user.service';
@Module({
imports: [
DynamooseModule.forFeature([{
name: 'User',
schema: UserSchema,
options: {
tableName: 'user',
},
}]),
],
providers: [
UserService,
...
],
})
export class UserModule {}
options.tableName
is optional. If it is not provided,name
will be used as the table name.
There is also forFeatureAsync(factories?: AsyncModelFactory[])
if you want to use a factory with dependency injection. Notes that the first parameter of the useFactory
callback is reserved for future use, so please just add _,
to ignore it.
The following example will use USER_TABLE_NAME
environment variable as the table name.
import { DynamooseModule } from 'nestjs-dynamoose';
import { UserSchema } from './user.schema';
import { UserService } from './user.service';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
DynamooseModule.forFeatureAsync([
{
name: 'User',
useFactory: (_, configService: ConfigService) => {
return {
schema: UserSchema,
options: {
tableName: configService.get<string>('USER_TABLE_NAME'),
},
};
},
inject: [ConfigService],
},
]),
],
providers: [
UserService,
...
],
})
export class UserModule {}
4. Inject and use your model
src/user/user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel, Model } from 'nestjs-dynamoose';
import { User, UserKey } from './user.interface';
@Injectable()
export class UserService {
constructor(
@InjectModel('User')
private userModel: Model<User, UserKey>,
) {}
create(user: User) {
return this.userModel.create(user);
}
update(key: UserKey, user: Partial<User>) {
return this.userModel.update(key, user);
}
findOne(key: UserKey) {
return this.userModel.get(key);
}
findAll() {
return this.userModel.scan().exec();
}
}
1. Transaction Support
Both User
and Account
model objects will commit in same transaction.
import { Injectable } from '@nestjs/common';
import { InjectModel, Model, TransactionSupport } from 'nestjs-dynamoose';
import { User, UserKey } from './user.interface';
import { Account, AccountKey } from './account.interface';
@Injectable()
export class UserService extends TransactionSupport {
constructor(
@InjectModel('User')
private userModel: Model<User, UserKey>,
@InjectModel('Account')
private accountModel: Model<Account, AccountKey>,
) {
super();
}
async create(user: User, account: Account) {
await this.transaction([
this.userModel.transaction.create(user),
this.accountModel.transaction.create(account),
]);
}
}
2. Serializers Support
Define the additional serializers
under DynamooseModule.forFeature()
.
@Module({
imports: [
DynamooseModule.forFeature([
{
name: 'User',
schema: UserSchema,
serializers: {
frontend: { exclude: ['status'] },
},
},
]),
],
...
})
export class UserModule {}
Call the serialize
function to exclude the status
field.
@Injectable()
export class UserService {
...
async create(user: User) {
const createdUser = await this.userModel.create(user);
return createdUser.serialize('frontend');
}
...
}
Dynamoose module for Nest is MIT licensed.