Skip to content

Commit 272f883

Browse files
authored
feat: add utilities for http headers (#157)
1 parent 56bfe0a commit 272f883

File tree

4 files changed

+241
-2
lines changed

4 files changed

+241
-2
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,12 @@ Instead of adding helpers to `req` and `res`, h3 exposes them as composable util
123123
- `useQuery(req)`
124124
- `send(res, data, type?)`
125125
- `sendRedirect(res, location, code=302)`
126-
- `appendHeader(res, name, value)`
126+
- `getRequestHeaders(event, headers)` (alias: `getHeaders`)
127+
- `getRequestHeader(event, name)` (alias: `getHeader`)
128+
- `setResponseHeaders(event, headers)` (alias: `setHeaders`)
129+
- `setResponseHeader(event, name, value)` (alias: `setHeader`)
130+
- `appendResponseHeaders(event, headers)` (alias: `appendHeaders`)
131+
- `appendResponseHeader(event, name, value)` (alias: `appendHeader`)
127132
- `createError({ statusCode, statusMessage, data? })`
128133
- `sendError(res, error, debug?)`
129134
- `defineHandle(handle)`

src/utils/request.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,18 @@ export function assertMethod (event: CompatibilityEvent, expected: HTTPMethod |
4343
})
4444
}
4545
}
46+
47+
export function getRequestHeaders (event: CompatibilityEvent): CompatibilityEvent['req']['headers'] {
48+
return event.req.headers
49+
}
50+
51+
export const getHeaders = getRequestHeaders
52+
53+
export function getRequestHeader (event: CompatibilityEvent, name: string): CompatibilityEvent['req']['headers'][string] {
54+
const headers = getRequestHeaders(event)
55+
const value = headers[name.toLowerCase()]
56+
57+
return value
58+
}
59+
60+
export const getHeader = getRequestHeader

src/utils/response.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { OutgoingMessage } from 'http'
12
import { createError } from '../error'
23
import type { CompatibilityEvent } from '../event'
34
import { MIMES } from './consts'
@@ -34,7 +35,33 @@ export function sendRedirect (event: CompatibilityEvent, location: string, code
3435
return send(event, html, MIMES.html)
3536
}
3637

37-
export function appendHeader (event: CompatibilityEvent, name: string, value: string): void {
38+
export function getResponseHeaders (event: CompatibilityEvent): ReturnType<CompatibilityEvent['res']['getHeaders']> {
39+
return event.res.getHeaders()
40+
}
41+
42+
export function getResponseHeader (event: CompatibilityEvent, name: string): ReturnType<CompatibilityEvent['res']['getHeader']> {
43+
return event.res.getHeader(name)
44+
}
45+
46+
export function setResponseHeaders (event: CompatibilityEvent, headers: Record<string, Parameters<OutgoingMessage['setHeader']>[1]>): void {
47+
Object.entries(headers).forEach(([name, value]) => event.res.setHeader(name, value))
48+
}
49+
50+
export const setHeaders = setResponseHeaders
51+
52+
export function setResponseHeader (event: CompatibilityEvent, name: string, value: Parameters<OutgoingMessage['setHeader']>[1]): void {
53+
event.res.setHeader(name, value)
54+
}
55+
56+
export const setHeader = setResponseHeader
57+
58+
export function appendResponseHeaders (event: CompatibilityEvent, headers: Record<string, string>): void {
59+
Object.entries(headers).forEach(([name, value]) => appendResponseHeader(event, name, value))
60+
}
61+
62+
export const appendHeaders = appendResponseHeaders
63+
64+
export function appendResponseHeader (event: CompatibilityEvent, name: string, value: string): void {
3865
let current = event.res.getHeader(name)
3966

4067
if (!current) {
@@ -49,6 +76,8 @@ export function appendHeader (event: CompatibilityEvent, name: string, value: st
4976
event.res.setHeader(name, current.concat(value))
5077
}
5178

79+
export const appendHeader = appendResponseHeader
80+
5281
export function isStream (data: any) {
5382
return data && typeof data === 'object' && typeof data.pipe === 'function' && typeof data.on === 'function'
5483
}

test/header.test.ts

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import supertest, { SuperTest, Test } from 'supertest'
2+
import { describe, it, expect, beforeEach } from 'vitest'
3+
import {
4+
createApp,
5+
App,
6+
getRequestHeaders,
7+
getHeaders,
8+
getRequestHeader,
9+
getHeader,
10+
setResponseHeaders,
11+
setHeaders,
12+
setResponseHeader,
13+
setHeader,
14+
appendResponseHeaders,
15+
appendHeaders,
16+
appendResponseHeader,
17+
appendHeader
18+
} from '../src'
19+
20+
describe('', () => {
21+
let app: App
22+
let request: SuperTest<Test>
23+
24+
beforeEach(() => {
25+
app = createApp({ debug: false })
26+
request = supertest(app)
27+
})
28+
29+
describe('getRequestHeaders', () => {
30+
it('can return request headers', async () => {
31+
app.use('/', (request) => {
32+
const headers = getRequestHeaders(request)
33+
expect(headers).toEqual(request.headers)
34+
})
35+
await request.get('/').set('Accept', 'application/json')
36+
})
37+
})
38+
39+
describe('getHeaders', () => {
40+
it('can return request headers', async () => {
41+
app.use('/', (request) => {
42+
const headers = getHeaders(request)
43+
expect(headers).toEqual(request.headers)
44+
})
45+
await request.get('/').set('Accept', 'application/json')
46+
})
47+
})
48+
49+
describe('getRequestHeader', () => {
50+
it('can return a value of request header corresponding to the given name', async () => {
51+
app.use('/', (request) => {
52+
expect(getRequestHeader(request, 'accept')).toEqual('application/json')
53+
expect(getRequestHeader(request, 'Accept')).toEqual('application/json')
54+
})
55+
await request.get('/').set('Accept', 'application/json')
56+
})
57+
})
58+
59+
describe('getHeader', () => {
60+
it('can return a value of request header corresponding to the given name', async () => {
61+
app.use('/', (request) => {
62+
expect(getHeader(request, 'accept')).toEqual('application/json')
63+
expect(getHeader(request, 'Accept')).toEqual('application/json')
64+
})
65+
await request.get('/').set('Accept', 'application/json')
66+
})
67+
})
68+
69+
describe('setResponseHeaders', () => {
70+
it('can set multiple values to multiple response headers corresponding to the given object', async () => {
71+
app.use('/', (request) => {
72+
setResponseHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1', 'Nuxt-HTTP-Header-2': 'string-value-2' })
73+
})
74+
const result = await request.get('/')
75+
expect(result.headers['nuxt-http-header-1']).toEqual('string-value-1')
76+
expect(result.headers['nuxt-http-header-2']).toEqual('string-value-2')
77+
})
78+
})
79+
80+
describe('setHeaders', () => {
81+
it('can set multiple values to multiple response headers corresponding to the given object', async () => {
82+
app.use('/', (request) => {
83+
setHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1', 'Nuxt-HTTP-Header-2': 'string-value-2' })
84+
})
85+
const result = await request.get('/')
86+
expect(result.headers['nuxt-http-header-1']).toEqual('string-value-1')
87+
expect(result.headers['nuxt-http-header-2']).toEqual('string-value-2')
88+
})
89+
})
90+
91+
describe('setResponseHeader', () => {
92+
it('can set a string value to response header corresponding to the given name', async () => {
93+
app.use('/', (request) => {
94+
setResponseHeader(request, 'Nuxt-HTTP-Header', 'string-value')
95+
})
96+
const result = await request.get('/')
97+
expect(result.headers['nuxt-http-header']).toEqual('string-value')
98+
})
99+
100+
it('can set a number value to response header corresponding to the given name', async () => {
101+
app.use('/', (request) => {
102+
setResponseHeader(request, 'Nuxt-HTTP-Header', 12345)
103+
})
104+
const result = await request.get('/')
105+
expect(result.headers['nuxt-http-header']).toEqual('12345')
106+
})
107+
108+
it('can set an array value to response header corresponding to the given name', async () => {
109+
app.use('/', (request) => {
110+
setResponseHeader(request, 'Nuxt-HTTP-Header', ['value 1', 'value 2'])
111+
setResponseHeader(request, 'Nuxt-HTTP-Header', ['value 3', 'value 4'])
112+
})
113+
const result = await request.get('/')
114+
expect(result.headers['nuxt-http-header']).toEqual('value 3, value 4')
115+
})
116+
})
117+
118+
describe('setHeader', () => {
119+
it('can set a string value to response header corresponding to the given name', async () => {
120+
app.use('/', (request) => {
121+
setHeader(request, 'Nuxt-HTTP-Header', 'string-value')
122+
})
123+
const result = await request.get('/')
124+
expect(result.headers['nuxt-http-header']).toEqual('string-value')
125+
})
126+
127+
it('can set a number value to response header corresponding to the given name', async () => {
128+
app.use('/', (request) => {
129+
setHeader(request, 'Nuxt-HTTP-Header', 12345)
130+
})
131+
const result = await request.get('/')
132+
expect(result.headers['nuxt-http-header']).toEqual('12345')
133+
})
134+
135+
it('can set an array value to response header corresponding to the given name', async () => {
136+
app.use('/', (request) => {
137+
setHeader(request, 'Nuxt-HTTP-Header', ['value 1', 'value 2'])
138+
setHeader(request, 'Nuxt-HTTP-Header', ['value 3', 'value 4'])
139+
})
140+
const result = await request.get('/')
141+
expect(result.headers['nuxt-http-header']).toEqual('value 3, value 4')
142+
})
143+
})
144+
145+
describe('appendResponseHeaders', () => {
146+
it('can append multiple string values to multiple response header corresponding to the given object', async () => {
147+
app.use('/', (request) => {
148+
appendResponseHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1-1', 'Nuxt-HTTP-Header-2': 'string-value-2-1' })
149+
appendResponseHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1-2', 'Nuxt-HTTP-Header-2': 'string-value-2-2' })
150+
})
151+
const result = await request.get('/')
152+
expect(result.headers['nuxt-http-header-1']).toEqual('string-value-1-1, string-value-1-2')
153+
expect(result.headers['nuxt-http-header-2']).toEqual('string-value-2-1, string-value-2-2')
154+
})
155+
})
156+
157+
describe('appendHeaders', () => {
158+
it('can append multiple string values to multiple response header corresponding to the given object', async () => {
159+
app.use('/', (request) => {
160+
appendHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1-1', 'Nuxt-HTTP-Header-2': 'string-value-2-1' })
161+
appendHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1-2', 'Nuxt-HTTP-Header-2': 'string-value-2-2' })
162+
})
163+
const result = await request.get('/')
164+
expect(result.headers['nuxt-http-header-1']).toEqual('string-value-1-1, string-value-1-2')
165+
expect(result.headers['nuxt-http-header-2']).toEqual('string-value-2-1, string-value-2-2')
166+
})
167+
})
168+
169+
describe('appendResponseHeader', () => {
170+
it('can append a value to response header corresponding to the given name', async () => {
171+
app.use('/', (request) => {
172+
appendResponseHeader(request, 'Nuxt-HTTP-Header', 'value 1')
173+
appendResponseHeader(request, 'Nuxt-HTTP-Header', 'value 2')
174+
})
175+
const result = await request.get('/')
176+
expect(result.headers['nuxt-http-header']).toEqual('value 1, value 2')
177+
})
178+
})
179+
180+
describe('appendHeader', () => {
181+
it('can append a value to response header corresponding to the given name', async () => {
182+
app.use('/', (request) => {
183+
appendHeader(request, 'Nuxt-HTTP-Header', 'value 1')
184+
appendHeader(request, 'Nuxt-HTTP-Header', 'value 2')
185+
})
186+
const result = await request.get('/')
187+
expect(result.headers['nuxt-http-header']).toEqual('value 1, value 2')
188+
})
189+
})
190+
})

0 commit comments

Comments
 (0)