Skip to content

Commit

Permalink
feat(express): add support for multer.none
Browse files Browse the repository at this point in the history
Adds an interceptor for multer's none option https://github.com/expressjs/multer#none. This allows for Nest.js users to process
`multipart/form-data` that does not include any files.
  • Loading branch information
mathewtrivett committed May 25, 2023
1 parent a1f16ae commit 009affa
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/platform-express/multer/interceptors/index.ts
Expand Up @@ -2,3 +2,4 @@ export * from './any-files.interceptor';
export * from './file-fields.interceptor';
export * from './file.interceptor';
export * from './files.interceptor';
export * from './no-files.interceptor';
@@ -0,0 +1,56 @@
import {
CallHandler,
ExecutionContext,
Inject,
mixin,
NestInterceptor,
Optional,
Type,
} from '@nestjs/common';
import * as multer from 'multer';
import { Observable } from 'rxjs';
import { MULTER_MODULE_OPTIONS } from '../files.constants';
import { MulterModuleOptions } from '../interfaces';
import { MulterOptions } from '../interfaces/multer-options.interface';
import { transformException } from '../multer/multer.utils';

type MulterInstance = any;

export function NoFilesInterceptor(
localOptions?: MulterOptions,
): Type<NestInterceptor> {
class MixinInterceptor implements NestInterceptor {
protected multer: MulterInstance;

constructor(
@Optional()
@Inject(MULTER_MODULE_OPTIONS)
options: MulterModuleOptions = {},
) {
this.multer = (multer as any)({
...options,
...localOptions,
});
}

async intercept(
context: ExecutionContext,
next: CallHandler,
): Promise<Observable<any>> {
const ctx = context.switchToHttp();

await new Promise<void>((resolve, reject) =>
this.multer.none()(ctx.getRequest(), ctx.getResponse(), (err: any) => {
if (err) {
const error = transformException(err);
return reject(error);
}
resolve();
}),
);
return next.handle();
}
}
const Interceptor = mixin(MixinInterceptor);
return Interceptor;
}
@@ -0,0 +1,44 @@
import { CallHandler } from '@nestjs/common';
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
import { expect } from 'chai';
import { of } from 'rxjs';
import * as sinon from 'sinon';
import { NoFilesInterceptor } from '../../../multer/interceptors/no-files.interceptor';

describe('NoFilesInterceptor', () => {
it('should return metatype with expected structure', async () => {
const targetClass = NoFilesInterceptor();
expect(targetClass.prototype.intercept).to.not.be.undefined;
});
describe('intercept', () => {
let handler: CallHandler;
beforeEach(() => {
handler = {
handle: () => of('test'),
};
});
it('should call none() with expected params', async () => {
const target = new (NoFilesInterceptor())();

const callback = (req, res, next) => next();
const noneSpy = sinon
.stub((target as any).multer, 'none')
.returns(callback);

await target.intercept(new ExecutionContextHost([]), handler);

expect(noneSpy.called).to.be.true;
});
it('should transform exception', async () => {
const target = new (NoFilesInterceptor())();
const err = {};
const callback = (req, res, next) => next(err);
(target as any).multer = {
array: () => callback,
};
(target.intercept(new ExecutionContextHost([]), handler) as any).catch(
error => expect(error).to.not.be.undefined,
);
});
});
});

0 comments on commit 009affa

Please sign in to comment.