Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions lib/interfaces/serve-static-options.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ export interface ServeStaticModuleOptions {
serveRoot?: string;
/**
* Paths to exclude when serving the static app. WARNING! Not supported by `fastify`. If you use `fastify`, you can exclude routes using regexp (set the `renderPath` to a regular expression) instead.
* Supports either an array of string paths or a regular expression.
*/
exclude?: string[];
exclude?: string[] | RegExp;
/**
* Serve static options (static files)
* Passed down to the underlying either `express.static` or `fastify-static.send`
Expand Down Expand Up @@ -148,8 +149,10 @@ export interface ServeStaticModuleOptionsFactory {
/**
* @publicApi
*/
export interface ServeStaticModuleAsyncOptions
extends Pick<ModuleMetadata, 'imports'> {
export interface ServeStaticModuleAsyncOptions extends Pick<
ModuleMetadata,
'imports'
> {
isGlobal?: boolean;
useExisting?: Type<ServeStaticModuleOptionsFactory>;
useClass?: Type<ServeStaticModuleOptionsFactory>;
Expand Down
18 changes: 12 additions & 6 deletions lib/utils/is-route-excluded.util.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import { pathToRegexp } from 'path-to-regexp';

export const isRouteExcluded = (req: any, paths: string[] = []) => {
export const isRouteExcluded = (req: any, paths: string[] | RegExp = []) => {
const queryParamsIndex = req.originalUrl.indexOf('?');
const pathname =
queryParamsIndex >= 0
? req.originalUrl.slice(0, queryParamsIndex)
: req.originalUrl;

if (paths instanceof RegExp) {
return paths.test(pathname);
}

return paths.some((path) => {
const { regexp } = pathToRegexp(path);
const queryParamsIndex = req.originalUrl.indexOf('?');
const pathname =
queryParamsIndex >= 0
? req.originalUrl.slice(0, queryParamsIndex)
: req.originalUrl;

if (!regexp.exec(pathname + '/')) {
return false;
}

return true;
});
};
33 changes: 33 additions & 0 deletions tests/e2e/express-adapter.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,39 @@ describe('Express adapter', () => {
});
});

describe('when exclude is a RegExp', () => {
beforeAll(async () => {
app = await NestFactory.create(AppModule.withRegexExclude(), {
logger: new NoopLogger()
});

server = app.getHttpServer();
await app.init();
});

describe('GET /api', () => {
it('should return 404 for excluded route', async () => {
return request(server)
.get('/api')
.expect(404)
.expect(/Not Found/);
});
});

describe('GET /', () => {
it('should return HTML file', async () => {
return request(server)
.get('/')
.expect(200)
.expect('Content-Type', /html/);
});
});

afterAll(async () => {
await app.close();
});
});

describe('when "fallthrough" option is set to "false"', () => {
beforeAll(async () => {
app = await NestFactory.create(AppModule.withoutFallthrough(), {
Expand Down
12 changes: 12 additions & 0 deletions tests/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,16 @@ export class AppModule {
]
};
}

static withRegexExclude() {
return {
module: AppModule,
imports: [
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'client'),
exclude: /^\/api(\/.*)?$/
})
]
};
}
}