Skip to content

Commit

Permalink
#27: add registration with factory method support in nestjs plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
mahendraHegde committed May 30, 2024
1 parent 49b43ff commit 48803ac
Show file tree
Hide file tree
Showing 15 changed files with 231 additions and 32 deletions.
9 changes: 9 additions & 0 deletions .changeset/pink-drinks-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@node-idempotency/express": patch
"@node-idempotency/fastify": patch
"@node-idempotency/nestjs": patch
"@node-idempotency/shared": patch
"@node-idempotency/core": patch
---

add registration with factory method support in nestjs plugin
6 changes: 3 additions & 3 deletions Mermaid.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ sequenceDiagram
Server->>Store: Store Response(Idempotency-Key=1)
activate Store
deactivate Store
alt Timed Out/Server Crash/Connection Lost
Server-xClient: No Repsponse
else Client Crash
Expand Down Expand Up @@ -42,7 +42,7 @@ sequenceDiagram
Server->>Store: Check Idempotency-Key=2 (In-Progress)
activate Store
deactivate Store
Server->>Client2: 409 Conflict, Retry-After=1
Server->>Client2: 409 Conflict, Retry-After=1
deactivate Client2
Server->>Client: 201 Created
Expand All @@ -58,4 +58,4 @@ sequenceDiagram
Server->>Client2: 201 Created
deactivate Client2
deactivate Server
```
```
7 changes: 5 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ and powers,
- [`@node-idempotency/fastify`](https://www.npmjs.com/package/@node-idempotency/fastify) - Plug and Play `fastify` plugin for `@node-idempotency/core`

---

#### How?

![No Image](flow.png)

---
Expand Down Expand Up @@ -117,10 +119,11 @@ Other packages in the monorepo are, click on the links to read detailed uses of

Read more [here](./Contributing.md)


---

#### Release

1. pnpm changeset
2. commit changes
3. pnpm prepare:publish
4. pnpm publish -r
4. pnpm publish -r
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"build": "pnpm --filter @node-idempotency/* build",
"build:clean": "find packages/* -type d -name 'dist' -exec rm -rf {} \\;",
"typecheck": "pnpm --filter @node-idempotency/* typecheck",
"precommit": "pnpm build && pnpm format && pnpm lint:fix && pnpm test:e2e",
"precommit": "pnpm format && pnpm lint:fix && pnpm build && pnpm test:e2e",
"prepare:publish": "pnpm changeset version && pnpm install && pnpm precommit"
},
"keywords": [
Expand Down
5 changes: 3 additions & 2 deletions packages/core/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ and powers
if above packages dont meet your needs, you can utilise the core package directly to tweek it as per your needs.

---

#### How?
![No Image](../../flow.png)
---

## ![No Image](../../flow.png)

##### install

Expand Down
5 changes: 3 additions & 2 deletions packages/plugin-express/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ Network requests are unpredictable; clients/proxies may send duplicate or concur
- <i>[RFC](https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/) compliant: </i> Adheres to standards for compatibility with other systems/clients.

---

#### How?
![No Image](../../flow.png)
---

## ![No Image](../../flow.png)

##### instal

Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-fastify/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ Network requests are unpredictable; clients/proxies may send duplicate or concur
---

#### How?
![No Image](../../flow.png)
---

## ![No Image](../../flow.png)

##### instal

Expand Down
37 changes: 37 additions & 0 deletions packages/plugin-nestjs/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Network requests are unpredictable; clients/proxies may send duplicate or concur
---

#### How?

![No Image](../../flow.png)

---
Expand Down Expand Up @@ -49,6 +50,42 @@ import { NodeIdempotencyModule } from '@node-idempotency/nestjs';
})
export class AppModule {}

// OR using factory method

import { NodeIdempotencyModule } from '@node-idempotency/nestjs';
import { type DynamicModule, Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";

@Module({})
export class AppModule {
static forRootAsync(): DynamicModule {
return {
global: true,
module: AppModule,
controllers: [AppController],
imports: [
NodeIdempotencyModule.forRootAsync({
imports: [ConfigModule.forRoot()],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
return {
storage: {
adapter: StorageAdapterEnum.redis,
options: {
url: configService.get("REDIS_URL"),
},
},
cacheTTLMS: configService.get("CACHE_TTL"),
...idempotencyOptions, // additional idempotency options
};
},
}),
],
};
}
}


```

- `storage.adapter` can either be `memory`, `redis` or an instance of [`Storage`](https://github.com/mahendraHegde/node-idempotency/tree/main/packages/storage) interface.
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-nestjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"rxjs": "^7.8.1"
},
"devDependencies": {
"@nestjs/config": "^3.2.2",
"@nestjs/platform-fastify": "^10.3.8",
"@types/express": "^4.17.21",
"@types/supertest": "^6.0.2",
Expand Down
59 changes: 42 additions & 17 deletions packages/plugin-nestjs/src/node-idempotency.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Module,
type OnModuleDestroy,
Inject,
type Provider,
} from "@nestjs/common";
import { NodeIdempotencyInterceptor } from "./interceptors/node-idempotency.iterceptor";
import {
Expand All @@ -11,6 +12,7 @@ import {
} from "@node-idempotency/shared";
import { IDEMPOTENCY_OPTIONS, IDEMPOTENCY_STORAGE } from "./constants";
import { StorageAdapter } from "@node-idempotency/storage";
import { type RootAsyncRegisterOptions } from "./types";

@Module({
exports: [
Expand All @@ -22,33 +24,56 @@ import { StorageAdapter } from "@node-idempotency/storage";
export class NodeIdempotencyModule implements OnModuleDestroy {
constructor(
@Inject(IDEMPOTENCY_STORAGE)
private readonly stoarge: StorageAdapter,
private readonly storage: StorageAdapter,
) {}

async onModuleDestroy(): Promise<void> {
if (typeof this.stoarge.disconnect === "function") {
await this.stoarge.disconnect();
if (typeof this.storage.disconnect === "function") {
await this.storage.disconnect();
}
}

static forRootAsync(options: IdempotencyPluginOptions): DynamicModule {
static async forRootAsync(
registerOptions: RootAsyncRegisterOptions,
): Promise<DynamicModule> {
const providers = await this.buildProviders(registerOptions);
return {
global: true,
module: NodeIdempotencyModule,
providers: [
NodeIdempotencyInterceptor,
{
provide: IDEMPOTENCY_STORAGE,
useFactory: async () => {
return await buildStorageAdapter(options.storage);
},
},
{
provide: IDEMPOTENCY_OPTIONS,
useValue: options,
},
],
providers,
imports: "imports" in registerOptions ? registerOptions.imports : [],
exports: [NodeIdempotencyInterceptor],
};
}

private static async buildProviders(
registerOptions: RootAsyncRegisterOptions,
): Promise<Provider[]> {
const providers: Provider[] = [NodeIdempotencyInterceptor];
const storageProvider = {
provide: IDEMPOTENCY_STORAGE,
useFactory: async (options: IdempotencyPluginOptions) => {
return await buildStorageAdapter(options.storage);
},
inject: [IDEMPOTENCY_OPTIONS],
};

if ("storage" in registerOptions) {
providers.push({
provide: IDEMPOTENCY_OPTIONS,
useValue: registerOptions,
});
} else if (
"useFactory" in registerOptions &&
typeof registerOptions.useFactory === "function"
) {
providers.push({
provide: IDEMPOTENCY_OPTIONS,
useFactory: registerOptions.useFactory,
inject: registerOptions.inject,
});
}
providers.push(storageProvider);
return providers;
}
}
16 changes: 16 additions & 0 deletions packages/plugin-nestjs/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
import {
type InjectionToken,
type ModuleMetadata,
type OptionalFactoryDependency,
} from "@nestjs/common";
import { type IdempotencyPluginOptions } from "@node-idempotency/shared";

export interface SerializedAPIException {
message: string;
name?: string;
options?: Record<string, unknown>;
response?: { message: string; statusCode: number };
status?: number;
}

export type RootAsyncRegisterOptions =
| IdempotencyPluginOptions
| (Pick<ModuleMetadata, "imports"> & {
useFactory?: (
...args: unknown[]
) => Promise<IdempotencyPluginOptions> | IdempotencyPluginOptions;
inject?: Array<InjectionToken | OptionalFactoryDependency>;
});
15 changes: 13 additions & 2 deletions packages/plugin-nestjs/tests/e2e/idempotency.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@ import { FastifyAdapter } from "@nestjs/platform-fastify";
import { HTTPHeaderEnum } from "@node-idempotency/shared";

import * as request from "supertest";
import { TestModuleMemory, TestModuleRedis } from "./modules/test/test.module";
import {
TestModuleMemory,
TestModuleMemoryithFactory,
TestModuleRedis,
TestModuleRedisWithFactory,
} from "./modules/test/test.module";
import { type Server } from "net";
const idempotencyKey = "Idempotency-Key";
const IDEMPOTENCY_REPLAYED_HEADER = HTTPHeaderEnum.idempotentReplayed;

describe("Node-Idempotency", () => {
["fastify", "express"].forEach((adapter) => {
[TestModuleMemory, TestModuleRedis].forEach((TestModule) => {
[
TestModuleMemory,
TestModuleRedis,
TestModuleRedisWithFactory,
TestModuleMemoryithFactory,
].forEach((TestModule) => {
describe(`when ${adapter}:${TestModule.name}`, () => {
let server: Server;
let app: INestApplication;
Expand All @@ -23,6 +33,7 @@ describe("Node-Idempotency", () => {
redisServer = new RedisMemoryServer();
const port = await redisServer.getPort();
const host = await redisServer.getHost();
process.env.REDIS_URL = `redis://${host}:${port}`;
const module = await Test.createTestingModule({
imports: [TestModule.forRootAsync({ port, host })],
}).compile();
Expand Down
51 changes: 51 additions & 0 deletions packages/plugin-nestjs/tests/e2e/modules/test/test.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type DynamicModule, Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import {
NodeIdempotencyModule,
StorageAdapterEnum,
Expand Down Expand Up @@ -43,3 +44,53 @@ export class TestModuleRedis {
};
}
}

@Module({})
export class TestModuleRedisWithFactory {
static forRootAsync(): DynamicModule {
return {
global: true,
module: TestModuleRedisWithFactory,
controllers: [TestController],
imports: [
NodeIdempotencyModule.forRootAsync({
imports: [ConfigModule.forRoot()],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
return {
storage: {
adapter: StorageAdapterEnum.redis,
options: {
url: configService.get("REDIS_URL"),
},
},
cacheTTLMS: 1000,
};
},
}),
],
};
}
}
@Module({})
export class TestModuleMemoryithFactory {
static forRootAsync(): DynamicModule {
return {
global: true,
module: TestModuleMemoryithFactory,
controllers: [TestController],
imports: [
NodeIdempotencyModule.forRootAsync({
useFactory: async () => {
return {
storage: {
adapter: StorageAdapterEnum.memory,
},
cacheTTLMS: 1000,
};
},
}),
],
};
}
}
2 changes: 1 addition & 1 deletion packages/shared/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Hey there!!! Thanks for landing here, you are probably not interested in this pa

- [`@node-idempotency/express`](https://www.npmjs.com/package/@node-idempotency/express) - Plug and Play `express` middleware for `@node-idempotency/core`

- [`@node-idempotency/fastify`](https://www.npmjs.com/package/@node-idempotency/fastify) - Plug and Play `fastify` plugin for `@node-idempotency/core`
- [`@node-idempotency/fastify`](https://www.npmjs.com/package/@node-idempotency/fastify) - Plug and Play `fastify` plugin for `@node-idempotency/core`
Loading

0 comments on commit 48803ac

Please sign in to comment.