Skip to content

Commit 087aa6e

Browse files
authored
Log dev error in Server Router (#45951)
Fixes NEXT-561 ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md) ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] [e2e](https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md) ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm build && pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
1 parent c0431d0 commit 087aa6e

File tree

10 files changed

+91
-2
lines changed

10 files changed

+91
-2
lines changed

packages/next/src/build/webpack/loaders/next-app-loader.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ async function createAppRouteCode({
6262
import 'next/dist/server/node-polyfill-headers'
6363
6464
export * as handlers from ${JSON.stringify(resolvedPagePath)}
65+
export const resolvedPagePath = ${JSON.stringify(resolvedPagePath)}
6566
6667
export { requestAsyncStorage } from 'next/dist/client/components/request-async-storage'
6768
`

packages/next/src/server/future/route-handlers/app-route-route-handler.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ export type AppRouteModule = {
6161
* The exported async storage object for this worker/module.
6262
*/
6363
requestAsyncStorage: RequestAsyncStorage
64+
65+
/**
66+
* The absolute path to the module file
67+
*/
68+
resolvedPagePath: string
6469
}
6570

6671
/**
@@ -172,7 +177,26 @@ export class AppRouteRouteHandler implements RouteHandler<AppRouteRouteMatch> {
172177
if (!isHTTPMethod(req.method)) return handleBadRequestResponse
173178

174179
// Pull out the handlers from the app route module.
175-
const { handlers } = mod
180+
const { handlers, resolvedPagePath } = mod
181+
182+
if (process.env.NODE_ENV !== 'production') {
183+
// Print error in development if the exported handlers are in lowercase, only uppercase handlers are supported
184+
for (const invalidMethodName of [
185+
'get',
186+
'head',
187+
'options',
188+
'post',
189+
'put',
190+
'delete',
191+
'patch',
192+
]) {
193+
if ((handlers as any)[invalidMethodName]) {
194+
Log.error(
195+
`Detected lowercase method '${invalidMethodName}' in '${resolvedPagePath}'. Export the uppercase '${invalidMethodName.toUpperCase()}' method name to fix this error.`
196+
)
197+
}
198+
}
199+
}
176200

177201
// Check to see if the requested method is available.
178202
const handler: AppRouteHandlerFn | undefined = handlers[req.method]

test/e2e/app-dir/app-routes/app-custom-routes.test.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ createNextDescribe(
1414
// TODO-APP: enable after deploy support is added
1515
skipDeployment: true,
1616
},
17-
({ next }) => {
17+
({ next, isNextDev }) => {
1818
describe('basic fetch request with a response', () => {
1919
describe.each(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'])(
2020
'made via a %s request',
@@ -311,5 +311,33 @@ createNextDescribe(
311311
)
312312
})
313313
})
314+
315+
if (isNextDev) {
316+
describe('lowercase exports', () => {
317+
it.each([
318+
['get'],
319+
['head'],
320+
['options'],
321+
['post'],
322+
['put'],
323+
['delete'],
324+
['patch'],
325+
])(
326+
'should print an error when using lowercase %p in dev',
327+
async (method: string) => {
328+
await next.fetch('/lowercase/' + method)
329+
expect(next.cliOutput).toContain(
330+
`Detected lowercase method '${method}' in`
331+
)
332+
expect(next.cliOutput).toContain(
333+
`Export the uppercase '${method.toUpperCase()}' method name to fix this error.`
334+
)
335+
expect(next.cliOutput).toMatch(
336+
/Detected lowercase method '.+' in '.+\/route\.ts'\. Export the uppercase '.+' method name to fix this error\./
337+
)
338+
}
339+
)
340+
})
341+
}
314342
}
315343
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const handler = async (): Promise<Response> => {
2+
return new Response('hello, world')
3+
}
4+
5+
const del = handler
6+
export { del as delete }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const handler = async (): Promise<Response> => {
2+
return new Response('hello, world')
3+
}
4+
5+
export const get = handler
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const handler = async (): Promise<Response> => {
2+
return new Response('hello, world')
3+
}
4+
5+
export const head = handler
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const handler = async (): Promise<Response> => {
2+
return new Response('hello, world')
3+
}
4+
5+
export const options = handler
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const handler = async (): Promise<Response> => {
2+
return new Response('hello, world')
3+
}
4+
5+
export const patch = handler
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const handler = async (): Promise<Response> => {
2+
return new Response('hello, world')
3+
}
4+
5+
export const post = handler
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const handler = async (): Promise<Response> => {
2+
return new Response('hello, world')
3+
}
4+
5+
export const put = handler

0 commit comments

Comments
 (0)