Skip to content

Commit 40385ac

Browse files
committed
Validation pipe example
1 parent cc4ceb1 commit 40385ac

File tree

3 files changed

+57
-49
lines changed

3 files changed

+57
-49
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
"@types/jest": "^25.1.4",
3030
"@types/node": "^13.9.0",
3131
"@types/supertest": "^2.0.7",
32+
"class-transformer": "^0.3.2",
33+
"class-validator": "^0.13.1",
3234
"jest": "^25.1.0",
3335
"prettier": "^1.15.3",
3436
"rxjs": "^6.0.0",

src/index.spec.ts

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as request from 'supertest';
1+
import * as request from "supertest";
22

33
import { Test } from "@nestjs/testing";
44
import { INestApplication, INestMicroservice } from "@nestjs/common";
@@ -15,7 +15,7 @@ describe("json-rpc-e2e", () => {
1515
let service: ITestClientService;
1616
let unauthorizedService: ITestClientService;
1717

18-
describe('standalone', () => {
18+
describe("standalone", () => {
1919
beforeAll(async () => {
2020
let moduleRef = await Test.createTestingModule({
2121
controllers: [TestService]
@@ -45,6 +45,10 @@ describe("json-rpc-e2e", () => {
4545
expect(res).toStrictEqual({ test: "hi" });
4646
});
4747

48+
it(`should throw if sends an invalid DTO`, async () => {
49+
let res = service.invokeClientService({ test: "" });
50+
await expect(res).rejects.toThrow("hi");
51+
});
4852
it(`should fail to make a request with an unauthorized JsonRpcClient`, async () => {
4953
let result = unauthorizedService.invokeClientService({ test: "hi" });
5054
await expect(result).rejects.toThrowError("Forbidden resource");
@@ -61,7 +65,10 @@ describe("json-rpc-e2e", () => {
6165
});
6266

6367
it(`should fail to invoke unexposed methods`, async () => {
64-
const expectedCodedException = new CodedRpcException("Method not found: test.notExposed", 404);
68+
const expectedCodedException = new CodedRpcException(
69+
"Method not found: test.notExposed",
70+
404
71+
);
6572
const resp = service.notExposed({ test: "data" });
6673
await expect(resp).rejects.toThrowError(expectedCodedException);
6774
});
@@ -83,17 +90,17 @@ describe("json-rpc-e2e", () => {
8390
});
8491
});
8592

86-
describe('hybrid', () => {
93+
describe("hybrid", () => {
8794
beforeAll(async () => {
8895
let moduleRef = await Test.createTestingModule({
8996
controllers: [TestService]
9097
}).compile();
91-
98+
9299
app = moduleRef.createNestApplication();
93100

94101
server = new JsonRpcServer({
95-
path: '/rpc',
96-
adapter: app.getHttpAdapter(),
102+
path: "/rpc",
103+
adapter: app.getHttpAdapter()
97104
});
98105

99106
app.connectMicroservice({ strategy: server });
@@ -102,46 +109,46 @@ describe("json-rpc-e2e", () => {
102109
await app.init();
103110
});
104111

105-
it('should invoke RPC methods on incoming HTTP requests', async () => {
112+
it("should invoke RPC methods on incoming HTTP requests", async () => {
106113
await request(app.getHttpServer())
107-
.post('/rpc')
108-
.set('Authorization', 'Bearer xyz')
114+
.post("/rpc")
115+
.set("Authorization", "Bearer xyz")
109116
.send({
110-
jsonrpc: '2.0',
111-
method: 'test.invokeClientService',
112-
id: '1',
117+
jsonrpc: "2.0",
118+
method: "test.invokeClientService",
119+
id: "1",
113120
params: {
114-
test: 'hi',
115-
},
121+
test: "hi"
122+
}
116123
})
117124
.expect({
118-
jsonrpc: '2.0',
119-
id: '1',
120-
result: { test: 'hi' }
125+
jsonrpc: "2.0",
126+
id: "1",
127+
result: { test: "hi" }
121128
});
122129
});
123130

124-
it('should wrap json-rpc errors in http 200', async () => {
131+
it("should wrap json-rpc errors in http 200", async () => {
125132
await request(app.getHttpServer())
126-
.post('/rpc')
127-
.set('Authorization', 'Bearer xyz')
128-
.send({
129-
jsonrpc: '2.0',
130-
method: 'test.notExposed',
131-
id: '1',
132-
params: {
133-
test: 'hi',
134-
},
135-
})
136-
.expect({
137-
jsonrpc: '2.0',
138-
id: '1',
139-
error: {
140-
code: 404,
141-
data: {},
142-
message: 'Method not found: test.notExposed',
143-
}
144-
});
133+
.post("/rpc")
134+
.set("Authorization", "Bearer xyz")
135+
.send({
136+
jsonrpc: "2.0",
137+
method: "test.notExposed",
138+
id: "1",
139+
params: {
140+
test: "hi"
141+
}
142+
})
143+
.expect({
144+
jsonrpc: "2.0",
145+
id: "1",
146+
error: {
147+
code: 404,
148+
data: {},
149+
message: "Method not found: test.notExposed"
150+
}
151+
});
145152
});
146153
});
147154
});

src/test-handler.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import {
1010
UseInterceptors,
1111
UseGuards,
1212
Scope,
13-
Inject
13+
ValidationPipe
1414
} from "@nestjs/common";
1515
import { Ctx } from "@nestjs/microservices";
1616

17+
import { IsNotEmpty } from "class-validator";
18+
1719
import { CodedRpcException, JsonRpcContext, RpcController, RpcMethod, RpcService } from ".";
1820

1921
const initialModuleState = {
@@ -83,6 +85,11 @@ class TestGuard implements CanActivate {
8385

8486
type IRpcTestService = RpcController<ITestClientService>;
8587

88+
export class TestDto {
89+
@IsNotEmpty()
90+
test!: string;
91+
}
92+
8693
@RpcService({
8794
namespace: "test"
8895
})
@@ -92,14 +99,6 @@ export class TestService implements IRpcTestService {
9299
DecorationsState.serviceConstructorCount = DecorationsState.serviceConstructorCount + 1;
93100
}
94101

95-
@UsePipes(TestPipe)
96-
@UseInterceptors(TestInterceptor)
97-
@UseGuards(TestGuard)
98-
@RpcMethod()
99-
public async invoke(params: { test: string }) {
100-
return Promise.resolve(params);
101-
}
102-
103102
@UsePipes(TestPipe)
104103
@UseInterceptors(TestInterceptor)
105104
@UseGuards(TestGuard)
@@ -110,10 +109,11 @@ export class TestService implements IRpcTestService {
110109
}
111110

112111
@UsePipes(TestPipe)
112+
@UsePipes(ValidationPipe)
113113
@UseInterceptors(TestInterceptor)
114114
@UseGuards(TestGuard)
115115
@RpcMethod()
116-
public async invokeClientService(params: { test: string }) {
116+
public async invokeClientService(params: TestDto) {
117117
return Promise.resolve(params);
118118
}
119119

@@ -131,7 +131,6 @@ export class TestService implements IRpcTestService {
131131
}
132132

133133
export interface ITestClientService {
134-
invoke(params: { test: string }): Promise<{ test: string }>;
135134
invokeClientService(params: { test: string }): Promise<{ test: string }>;
136135
testError(params: { errorTest: string }): Promise<void>;
137136
injectContext(params: {}): Promise<{ key: string | undefined }>;

0 commit comments

Comments
 (0)