Edge Cookies: Add .getWithOptions
method (#36943)
Hello, This is an iteration after first work at https://github.com/vercel/next.js/pull/36478. What that PR missed is a way to just get a cookie value. Well, this PR adds two new things: `cookies.get` returns the cookie value that could be `string | undefined`: ```js const response = new NextResponse() response.cookies.set('foo', 'bar', { path: '/test' }) const value = response.cookies.get('foo') console.log(value) // => 'bar' ``` Additionally, if you want to know all the cookie details, you can use `cookies.getWithOptions`: ```js const response = new NextResponse() response.cookies.set('foo', 'bar', { path: '/test' }) const { value, options } response.cookies.getWithOptions('foo') console.log(value) // => 'bar' console.log(options) // => { Path: '/test' } ```
This commit is contained in:
parent
5acf9db617
commit
cc8ab99a92
3 changed files with 69 additions and 26 deletions
|
@ -1,6 +1,11 @@
|
|||
import cookie from 'next/dist/compiled/cookie'
|
||||
import { CookieSerializeOptions } from '../types'
|
||||
|
||||
type GetWithOptionsOutput = {
|
||||
value: string | undefined
|
||||
options: { [key: string]: string }
|
||||
}
|
||||
|
||||
const normalizeCookieOptions = (options: CookieSerializeOptions) => {
|
||||
options = Object.assign({}, options)
|
||||
|
||||
|
@ -59,10 +64,22 @@ export class NextCookies extends Cookies {
|
|||
super(response.headers.get('cookie'))
|
||||
this.response = response
|
||||
}
|
||||
get = (...args: Parameters<Cookies['get']>) => {
|
||||
return this.getWithOptions(...args).value
|
||||
}
|
||||
getWithOptions = (
|
||||
...args: Parameters<Cookies['get']>
|
||||
): GetWithOptionsOutput => {
|
||||
const raw = super.get(...args)
|
||||
if (typeof raw !== 'string') return { value: raw, options: {} }
|
||||
const { [args[0]]: value, ...options } = cookie.parse(raw)
|
||||
return { value, options }
|
||||
}
|
||||
set = (...args: Parameters<Cookies['set']>) => {
|
||||
const isAlreadyAdded = super.has(args[0])
|
||||
const store = super.set(...args)
|
||||
const currentCookie = store.get(args[0])
|
||||
|
||||
super.set(...args)
|
||||
const currentCookie = super.get(args[0])
|
||||
|
||||
if (typeof currentCookie !== 'string') {
|
||||
throw new Error(
|
||||
|
@ -89,9 +106,9 @@ export class NextCookies extends Cookies {
|
|||
this.response.headers.append('set-cookie', currentCookie)
|
||||
}
|
||||
|
||||
return store
|
||||
return this
|
||||
}
|
||||
delete = (key: any, options: CookieSerializeOptions = {}) => {
|
||||
delete = (key: string, options: CookieSerializeOptions = {}) => {
|
||||
const isDeleted = super.delete(key)
|
||||
|
||||
if (isDeleted) {
|
||||
|
|
|
@ -10,9 +10,6 @@ export const middleware: NextMiddleware = async function (request) {
|
|||
const response = NextResponse.rewrite(`/rewrites/${bucket}`)
|
||||
response.cookies.set('bucket', bucket, { maxAge: 10 })
|
||||
return response
|
||||
} else {
|
||||
// check that `bucket` is type "string", not "any"
|
||||
bucket.toUpperCase()
|
||||
}
|
||||
|
||||
return NextResponse.rewrite(`/rewrites/${bucket}`)
|
||||
|
|
|
@ -34,26 +34,30 @@ it('reflect .set into `set-cookie`', async () => {
|
|||
|
||||
const response = new NextResponse()
|
||||
|
||||
response.cookies.set('foo', 'bar')
|
||||
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
|
||||
'foo=bar; Path=/'
|
||||
)
|
||||
expect(response.cookies.get('foo')).toBe('foo=bar; Path=/')
|
||||
expect(response.cookies.get('foo')).toBe(undefined)
|
||||
expect(response.cookies.getWithOptions('foo')).toEqual({
|
||||
value: undefined,
|
||||
options: {},
|
||||
})
|
||||
|
||||
response.cookies.set('foo', 'barz')
|
||||
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
|
||||
'foo=barz; Path=/'
|
||||
)
|
||||
expect(response.cookies.get('foo')).toBe('foo=barz; Path=/')
|
||||
response.cookies
|
||||
.set('foo', 'bar', { path: '/test' })
|
||||
.set('fooz', 'barz', { path: '/test2' })
|
||||
|
||||
response.cookies.set('fooz', 'barz')
|
||||
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
|
||||
'foo=barz; Path=/, fooz=barz; Path=/'
|
||||
)
|
||||
expect(response.cookies.get('foo')).toBe('bar')
|
||||
expect(response.cookies.get('fooz')).toBe('barz')
|
||||
|
||||
expect(response.cookies.getWithOptions('foo')).toEqual({
|
||||
value: 'bar',
|
||||
options: { Path: '/test' },
|
||||
})
|
||||
expect(response.cookies.getWithOptions('fooz')).toEqual({
|
||||
value: 'barz',
|
||||
options: { Path: '/test2' },
|
||||
})
|
||||
|
||||
response.cookies.set('foo', 'bar')
|
||||
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
|
||||
'foo=bar; Path=/, fooz=barz; Path=/'
|
||||
'foo=bar; Path=/test, fooz=barz; Path=/test2'
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -68,13 +72,23 @@ it('reflect .delete into `set-cookie`', async () => {
|
|||
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
|
||||
'foo=bar; Path=/'
|
||||
)
|
||||
expect(response.cookies.get('foo')).toBe('foo=bar; Path=/')
|
||||
|
||||
expect(response.cookies.get('foo')).toBe('bar')
|
||||
expect(response.cookies.getWithOptions('foo')).toEqual({
|
||||
value: 'bar',
|
||||
options: { Path: '/' },
|
||||
})
|
||||
|
||||
response.cookies.set('fooz', 'barz')
|
||||
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
|
||||
'foo=bar; Path=/, fooz=barz; Path=/'
|
||||
)
|
||||
expect(response.cookies.get('fooz')).toBe('fooz=barz; Path=/')
|
||||
|
||||
expect(response.cookies.get('fooz')).toBe('barz')
|
||||
expect(response.cookies.getWithOptions('fooz')).toEqual({
|
||||
value: 'barz',
|
||||
options: { Path: '/' },
|
||||
})
|
||||
|
||||
const firstDelete = response.cookies.delete('foo')
|
||||
expect(firstDelete).toBe(true)
|
||||
|
@ -83,13 +97,23 @@ it('reflect .delete into `set-cookie`', async () => {
|
|||
)
|
||||
|
||||
expect(response.cookies.get('foo')).toBe(undefined)
|
||||
expect(response.cookies.getWithOptions('foo')).toEqual({
|
||||
value: undefined,
|
||||
options: {},
|
||||
})
|
||||
|
||||
const secondDelete = response.cookies.delete('fooz')
|
||||
expect(secondDelete).toBe(true)
|
||||
|
||||
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
|
||||
'fooz=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT, foo=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT'
|
||||
)
|
||||
|
||||
expect(response.cookies.get('fooz')).toBe(undefined)
|
||||
expect(response.cookies.getWithOptions('fooz')).toEqual({
|
||||
value: undefined,
|
||||
options: {},
|
||||
})
|
||||
expect(response.cookies.size).toBe(0)
|
||||
})
|
||||
|
||||
|
@ -109,7 +133,12 @@ it('reflect .clear into `set-cookie`', async () => {
|
|||
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
|
||||
'foo=bar; Path=/'
|
||||
)
|
||||
expect(response.cookies.get('foo')).toBe('foo=bar; Path=/')
|
||||
|
||||
expect(response.cookies.get('foo')).toBe('bar')
|
||||
expect(response.cookies.getWithOptions('foo')).toEqual({
|
||||
value: 'bar',
|
||||
options: { Path: '/' },
|
||||
})
|
||||
|
||||
response.cookies.set('fooz', 'barz')
|
||||
expect(Object.fromEntries(response.headers.entries())['set-cookie']).toBe(
|
||||
|
|
Loading…
Reference in a new issue