Skip to content

Commit b25754d

Browse files
committed
feature(common): Add file interceptor for multer
1 parent acbeb1c commit b25754d

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import {
2+
CallHandler,
3+
ExecutionContext,
4+
Inject,
5+
mixin,
6+
NestInterceptor,
7+
Optional,
8+
Type,
9+
} from '@nestjs/common';
10+
import * as multer from 'multer';
11+
import { Observable } from 'rxjs';
12+
import { MULTER_MODULE_OPTIONS } from '../files.constants';
13+
import { MulterModuleOptions } from '../interfaces';
14+
import { MulterOptions } from '../interfaces/multer-options.interface';
15+
import { transformException } from '../multer/multer.utils';
16+
17+
type MulterInstance = any;
18+
19+
export function AnyFilesInterceptor(
20+
localOptions?: MulterOptions,
21+
): Type<NestInterceptor> {
22+
class MixinInterceptor implements NestInterceptor {
23+
protected multer: MulterInstance;
24+
25+
constructor(
26+
@Optional()
27+
@Inject(MULTER_MODULE_OPTIONS)
28+
options: MulterModuleOptions = {},
29+
) {
30+
this.multer = (multer as any)({
31+
...options,
32+
...localOptions,
33+
});
34+
}
35+
36+
async intercept(
37+
context: ExecutionContext,
38+
next: CallHandler,
39+
): Promise<Observable<any>> {
40+
const ctx = context.switchToHttp();
41+
42+
await new Promise((resolve, reject) =>
43+
this.multer.any()(
44+
ctx.getRequest(),
45+
ctx.getResponse(),
46+
(err: any) => {
47+
if (err) {
48+
const error = transformException(err);
49+
return reject(error);
50+
}
51+
resolve();
52+
},
53+
),
54+
);
55+
return next.handle();
56+
}
57+
}
58+
const Interceptor = mixin(MixinInterceptor);
59+
return Interceptor as Type<NestInterceptor>;
60+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { CallHandler } from '@nestjs/common';
2+
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
3+
import { expect } from 'chai';
4+
import { of } from 'rxjs';
5+
import * as sinon from 'sinon';
6+
import { AnyFilesInterceptor } from '../../../multer/interceptors/any-files.interceptor';
7+
8+
describe('FilesInterceptor', () => {
9+
it('should return metatype with expected structure', async () => {
10+
const targetClass = AnyFilesInterceptor();
11+
expect(targetClass.prototype.intercept).to.not.be.undefined;
12+
});
13+
describe('intercept', () => {
14+
let handler: CallHandler;
15+
beforeEach(() => {
16+
handler = {
17+
handle: () => of('test'),
18+
};
19+
});
20+
it('should call any() with expected params', async () => {
21+
const target = new (AnyFilesInterceptor())();
22+
23+
const callback = (req, res, next) => next();
24+
const arraySpy = sinon
25+
.stub((target as any).multer, 'any')
26+
.returns(callback);
27+
28+
await target.intercept(new ExecutionContextHost([]), handler);
29+
30+
expect(arraySpy.called).to.be.true;
31+
expect(arraySpy.calledWith()).to.be.true;
32+
});
33+
it('should transform exception', async () => {
34+
const target = new (AnyFilesInterceptor())();
35+
const err = {};
36+
const callback = (req, res, next) => next(err);
37+
38+
(target as any).multer = {
39+
any: () => callback,
40+
};
41+
(target.intercept(new ExecutionContextHost([]), handler) as any).catch(
42+
error => expect(error).to.not.be.undefined,
43+
);
44+
});
45+
});
46+
});

0 commit comments

Comments
 (0)