Skip to content

Commit

Permalink
fix: route matching for different patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
ggurkal committed Jul 2, 2021
1 parent 3eab34f commit 7f09043
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 11 deletions.
6 changes: 3 additions & 3 deletions lib/createHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
import { findRoute } from './internals/findRoute';
import { getFileDirectory } from './internals/getFileDirectory';
import { getCallerInfo } from './internals/getCallerInfo';
import { getParams } from './internals/getParams';
import { notFound } from './internals/notFound';
import { parseRequestUrl } from './internals/parseRequestUrl';
Expand All @@ -26,14 +26,14 @@ import { parseRequestUrl } from './internals/parseRequestUrl';
*/
export function createHandler(cls: new (...args: any[]) => any): NextApiHandler {
const instance = new cls();
const directory = getFileDirectory();
const [directory, fileName] = getCallerInfo();

return (req: NextApiRequest, res: NextApiResponse) => {
if (!req.url || !req.method) {
return notFound(req, res);
}

const path = parseRequestUrl(req.url, directory);
const path = parseRequestUrl(req, directory, fileName);
const [keys, match, method] = findRoute(cls, req.method, path);
if (!method) {
return notFound(req, res);
Expand Down
40 changes: 35 additions & 5 deletions lib/internals/parseRequestUrl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,52 @@ import { parseRequestUrl } from './parseRequestUrl';

describe('parseRequestUrl', () => {
it('Should return "/"', () => {
expect(parseRequestUrl('/api/user')).toStrictEqual('/');
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
expect(parseRequestUrl({ url: '/api/user' })).toStrictEqual('/');
});

it('Should return "/1"', () => {
expect(parseRequestUrl('/api/user/1')).toStrictEqual('/1');
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
expect(parseRequestUrl({ url: '/api/user/1' })).toStrictEqual('/1');
});

it('Should return "/1/articles"', () => {
expect(parseRequestUrl('/api/user/1/articles')).toStrictEqual('/1/articles');
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
expect(parseRequestUrl({ url: '/api/user/1/articles' })).toStrictEqual('/1/articles');
});

it('Should return "/" when directory name is a paremeter ([id])', () =>
expect(parseRequestUrl('/api/user/1', '/next-api-decorators/.next/server/pages/api/user/[id]')).toStrictEqual('/'));
expect(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
parseRequestUrl({ url: '/api/user/1' }, '/next-api-decorators/.next/server/pages/api/user/[id]')
).toStrictEqual('/'));

it('Should return "/articles" when directory name is a paremeter ([id])', () =>
expect(
parseRequestUrl('/api/user/1/articles', '/next-api-decorators/.next/server/pages/api/user/[id]')
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
parseRequestUrl({ url: '/api/user/1/articles' }, '/next-api-decorators/.next/server/pages/api/user/[id]')
).toStrictEqual('/articles'));

it('Should return "/" when the file name is "articles.js" which gets compiled from "articles/index.ts"', () =>
expect(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
parseRequestUrl({ url: '/api/articles' }, '/next-api-decorators/.next/server/pages/api', 'articles.js')
).toStrictEqual('/'));

it('Should return "/" when the file name starts with "[..."', () =>
expect(
parseRequestUrl(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
{ url: '/api/article/1', query: { id: '1' } },
'/next-api-decorators/.next/server/pages/api/article',
'[...id].js'
)
).toStrictEqual('/'));
});
26 changes: 23 additions & 3 deletions lib/internals/parseRequestUrl.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
export function parseRequestUrl(url: string, directoryPath?: string): string {
import { basename, extname } from 'path';
import type { NextApiRequest } from 'next';

export function parseRequestUrl(req: NextApiRequest, directoryPath?: string, fileName?: string): string {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const url = req.url!;
let path = url.split('?')[0].split('/').slice(3).join('/');

if (directoryPath) {
const pathRegExp = new RegExp(directoryPath.split('/.next/server/pages')[1].replace(/(\[\w+\])/, '(\\w+)'));
// In order for the main method (e.g: `@Get()`) to be matched,
// the path for catch all routes should be set to "/"
if (fileName?.startsWith('[...')) {
const qsKey = basename(fileName.replace('[...', '').replace(']', ''), extname(fileName));
/* istanbul ignore else */
if (req.query[qsKey]) {
path = '';
}
}

if (directoryPath && !fileName?.startsWith('[...')) {
const pathRegExp = new RegExp(
// "pages/api/articles/index.ts" is compiled into "pages/api/articles.js" which has to be appended to the directory path for parsing
(directoryPath + (fileName && !fileName.startsWith('[') ? basename(fileName, extname(fileName)) : ''))
.split('/.next/server/pages')[1]
.replace(/(\[\w+\])/, '(\\w+)')
);
/* istanbul ignore else */
if (pathRegExp.test(url)) {
path = url.replace(pathRegExp, '');
Expand Down

0 comments on commit 7f09043

Please sign in to comment.