Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hardyscc/nestjs-dynamoose

Dynamoose module for Nest
https://github.com/hardyscc/nestjs-dynamoose

dynamodb dynamoose nest nestjs

Last synced: about 2 months ago
JSON representation

Dynamoose module for Nest

Awesome Lists containing this project

README

        


Nest Logo

A progressive Node.js framework for building efficient and scalable server-side applications.


NPM Version
Package License
NPM Downloads
CI

## Description

[Dynamoose](https://dynamoosejs.com/) module for [Nest](https://github.com/nestjs/nest).

## Installation

```bash
$ npm install --save nestjs-dynamoose dynamoose
```

## Example Project

A [AWS NestJS Starter](https://github.com/hardyscc/aws-nestjs-starter) project has been created to demo the usage of this library.

## Quick Start

**1. Add import into your app module**

`src/app.module.ts`

```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`:

```ts
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`

```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`

```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`

```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.

```ts
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('USER_TABLE_NAME'),
},
};
},
inject: [ConfigService],
},
]),
],
providers: [
UserService,
...
],
})
export class UserModule {}
```

**4. Inject and use your model**

`src/user/user.service.ts`

```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,
) {}

create(user: User) {
return this.userModel.create(user);
}

update(key: UserKey, user: Partial) {
return this.userModel.update(key, user);
}

findOne(key: UserKey) {
return this.userModel.get(key);
}

findAll() {
return this.userModel.scan().exec();
}
}
```

## Additional Example

**1. Transaction Support**

Both `User` and `Account` model objects will commit in same transaction.

```ts
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,
@InjectModel('Account')
private accountModel: Model,
) {
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()`.

```ts
@Module({
imports: [
DynamooseModule.forFeature([
{
name: 'User',
schema: UserSchema,
serializers: {
frontend: { exclude: ['status'] },
},
},
]),
],
...
})
export class UserModule {}
```

Call the `serialize` function to exclude the `status` field.

```ts
@Injectable()
export class UserService {
...
async create(user: User) {
const createdUser = await this.userModel.create(user);
return createdUser.serialize('frontend');
}
...
}
```

## License

Dynamoose module for Nest is [MIT licensed](LICENSE).