Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add res.redirect response helper #14705

Merged
merged 22 commits into from
Jul 7, 2020
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cad0d12
Add `res.redirect` response helper
botv Jun 30, 2020
88cdad2
Merge branch 'canary' into response-helpers
botv Jun 30, 2020
514d6bf
Revert unnecessary changes
botv Jun 30, 2020
dff7b14
Match Express signature for `res.redirect`
botv Jun 30, 2020
001dcff
Merge branch 'response-helpers' of https://github.com/botv/next.js in…
botv Jun 30, 2020
a741d04
Add documentation for `res.redirect`
botv Jun 30, 2020
c7b82a7
Update packages/next/next-server/lib/utils.ts
botv Jul 1, 2020
f256bb4
Update packages/next/next-server/server/api-utils.ts
botv Jul 1, 2020
c43e2cd
Update packages/next/next-server/server/api-utils.ts
botv Jul 1, 2020
5ffe4f7
Update packages/next/next-server/server/api-utils.ts
botv Jul 1, 2020
3849a25
Fix errors from renamed parameter
botv Jul 1, 2020
2b4f62e
Add tests
botv Jul 1, 2020
a227119
Merge branch 'canary' into response-helpers
botv Jul 1, 2020
58c54fc
Change status code to 307
botv Jul 3, 2020
35d96f8
Merge branch 'response-helpers' of https://github.com/botv/next.js in…
botv Jul 3, 2020
540c229
Update examples with new redirect helper
botv Jul 3, 2020
76d702c
Update docs with new redirect helper
botv Jul 3, 2020
b0cc648
Merge branch 'canary' into response-helpers
botv Jul 3, 2020
6fb56ba
Merge branch 'canary' into response-helpers
botv Jul 5, 2020
babea12
Undo examples updates
botv Jul 5, 2020
7350832
Merge branch 'response-helpers' of https://github.com/botv/next.js in…
botv Jul 5, 2020
73c7fb7
Merge branch 'canary' into response-helpers
kodiakhq[bot] Jul 7, 2020
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
3 changes: 1 addition & 2 deletions docs/advanced-features/preview-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ export default async (req, res) => {

// Redirect to the path from the fetched post
// We don't redirect to req.query.slug as that might lead to open redirect vulnerabilities
res.writeHead(307, { Location: post.slug })
res.end()
res.redirect(post.slug)
}
```

Expand Down
1 change: 1 addition & 0 deletions docs/api-routes/response-helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ The included helpers are:
- `res.status(code)` - A function to set the status code. `code` must be a valid [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
- `res.json(json)` - Sends a JSON response. `json` must be a valid JSON object
- `res.send(body)` - Sends the HTTP response. `body` can be a `string`, an `object` or a `Buffer`
- `res.redirect([status,] path)` - Redirects to a specified path or URL. `status` must be a valid [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes). If not specified, `status` defaults to "302" "Found".
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be 307? @Timer

Copy link
Contributor Author

@botv botv Jul 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #14947 @SarKurd

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, maybe here should say res.redirect([status], path) instead of res.redirect([status,] path), right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 change: 1 addition & 0 deletions packages/next/next-server/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ export type NextApiResponse<T = any> = ServerResponse & {
*/
json: Send<T>
status: (statusCode: number) => NextApiResponse<T>
redirect: (statusOrUrl: string | number, url?: string) => NextApiResponse<T>

/**
* Set preview data for Next.js' prerender mode
Expand Down
21 changes: 21 additions & 0 deletions packages/next/next-server/server/api-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export async function apiResolver(
apiRes.status = (statusCode) => sendStatusCode(apiRes, statusCode)
apiRes.send = (data) => sendData(apiReq, apiRes, data)
apiRes.json = (data) => sendJson(apiRes, data)
apiRes.redirect = (statusOrUrl, url) => redirect(apiRes, statusOrUrl, url)
apiRes.setPreviewData = (data, options = {}) =>
setPreviewData(apiRes, data, Object.assign({}, apiContext, options))
apiRes.clearPreviewData = () => clearPreviewData(apiRes)
Expand Down Expand Up @@ -209,6 +210,26 @@ export function sendStatusCode(
return res
}

/**
*
* @param res response object
* @param [statusOrUrl] `HTTP` status code of redirect
* @param url URL of redirect
*/
export function redirect(
res: NextApiResponse,
statusOrUrl: string | number,
url?: string
): NextApiResponse<any> {
if (typeof statusOrUrl === 'string') {
url = statusOrUrl
statusOrUrl = 307
}

res.writeHead(statusOrUrl, { Location: url }).end()
return res
}

function sendEtagResponse(
req: NextApiRequest,
res: NextApiResponse,
Expand Down
3 changes: 3 additions & 0 deletions test/integration/api-support/pages/api/redirect-301.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default (req, res) => {
res.redirect(301, '/login')
}
3 changes: 3 additions & 0 deletions test/integration/api-support/pages/api/redirect-307.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default (req, res) => {
res.redirect('/login')
}
23 changes: 23 additions & 0 deletions test/integration/api-support/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,29 @@ function runTests(dev = false) {
expect(data).toEqual({ message: 'Parsed body' })
})

it('should redirect with status code 307', async () => {
const res = await fetchViaHTTP(appPort, '/api/redirect-307', null, {
redirect: 'manual',
})

expect(res.status).toEqual(307)
})

it('should redirect to login', async () => {
const res = await fetchViaHTTP(appPort, '/api/redirect-307', null, {})

expect(res.redirected).toBe(true)
expect(res.url).toContain('/login')
})

it('should redirect with status code 301', async () => {
const res = await fetchViaHTTP(appPort, '/api/redirect-301', null, {
redirect: 'manual',
})

expect(res.status).toEqual(301)
})

it('should return empty query object', async () => {
const data = await fetchViaHTTP(appPort, '/api/query', null, {}).then(
(res) => res.ok && res.json()
Expand Down