Skip to content

Commit

Permalink
feat: add utilities for http headers (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
NozomuIkuta committed Aug 3, 2022
1 parent 56bfe0a commit 272f883
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 2 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ Instead of adding helpers to `req` and `res`, h3 exposes them as composable util
- `useQuery(req)`
- `send(res, data, type?)`
- `sendRedirect(res, location, code=302)`
- `appendHeader(res, name, value)`
- `getRequestHeaders(event, headers)` (alias: `getHeaders`)
- `getRequestHeader(event, name)` (alias: `getHeader`)
- `setResponseHeaders(event, headers)` (alias: `setHeaders`)
- `setResponseHeader(event, name, value)` (alias: `setHeader`)
- `appendResponseHeaders(event, headers)` (alias: `appendHeaders`)
- `appendResponseHeader(event, name, value)` (alias: `appendHeader`)
- `createError({ statusCode, statusMessage, data? })`
- `sendError(res, error, debug?)`
- `defineHandle(handle)`
Expand Down
15 changes: 15 additions & 0 deletions src/utils/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,18 @@ export function assertMethod (event: CompatibilityEvent, expected: HTTPMethod |
})
}
}

export function getRequestHeaders (event: CompatibilityEvent): CompatibilityEvent['req']['headers'] {
return event.req.headers
}

export const getHeaders = getRequestHeaders

export function getRequestHeader (event: CompatibilityEvent, name: string): CompatibilityEvent['req']['headers'][string] {
const headers = getRequestHeaders(event)
const value = headers[name.toLowerCase()]

return value
}

export const getHeader = getRequestHeader
31 changes: 30 additions & 1 deletion src/utils/response.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { OutgoingMessage } from 'http'
import { createError } from '../error'
import type { CompatibilityEvent } from '../event'
import { MIMES } from './consts'
Expand Down Expand Up @@ -34,7 +35,33 @@ export function sendRedirect (event: CompatibilityEvent, location: string, code
return send(event, html, MIMES.html)
}

export function appendHeader (event: CompatibilityEvent, name: string, value: string): void {
export function getResponseHeaders (event: CompatibilityEvent): ReturnType<CompatibilityEvent['res']['getHeaders']> {
return event.res.getHeaders()
}

export function getResponseHeader (event: CompatibilityEvent, name: string): ReturnType<CompatibilityEvent['res']['getHeader']> {
return event.res.getHeader(name)
}

export function setResponseHeaders (event: CompatibilityEvent, headers: Record<string, Parameters<OutgoingMessage['setHeader']>[1]>): void {
Object.entries(headers).forEach(([name, value]) => event.res.setHeader(name, value))
}

export const setHeaders = setResponseHeaders

export function setResponseHeader (event: CompatibilityEvent, name: string, value: Parameters<OutgoingMessage['setHeader']>[1]): void {
event.res.setHeader(name, value)
}

export const setHeader = setResponseHeader

export function appendResponseHeaders (event: CompatibilityEvent, headers: Record<string, string>): void {
Object.entries(headers).forEach(([name, value]) => appendResponseHeader(event, name, value))
}

export const appendHeaders = appendResponseHeaders

export function appendResponseHeader (event: CompatibilityEvent, name: string, value: string): void {
let current = event.res.getHeader(name)

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

export const appendHeader = appendResponseHeader

export function isStream (data: any) {
return data && typeof data === 'object' && typeof data.pipe === 'function' && typeof data.on === 'function'
}
Expand Down
190 changes: 190 additions & 0 deletions test/header.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import supertest, { SuperTest, Test } from 'supertest'
import { describe, it, expect, beforeEach } from 'vitest'
import {
createApp,
App,
getRequestHeaders,
getHeaders,
getRequestHeader,
getHeader,
setResponseHeaders,
setHeaders,
setResponseHeader,
setHeader,
appendResponseHeaders,
appendHeaders,
appendResponseHeader,
appendHeader
} from '../src'

describe('', () => {
let app: App
let request: SuperTest<Test>

beforeEach(() => {
app = createApp({ debug: false })
request = supertest(app)
})

describe('getRequestHeaders', () => {
it('can return request headers', async () => {
app.use('/', (request) => {
const headers = getRequestHeaders(request)
expect(headers).toEqual(request.headers)
})
await request.get('/').set('Accept', 'application/json')
})
})

describe('getHeaders', () => {
it('can return request headers', async () => {
app.use('/', (request) => {
const headers = getHeaders(request)
expect(headers).toEqual(request.headers)
})
await request.get('/').set('Accept', 'application/json')
})
})

describe('getRequestHeader', () => {
it('can return a value of request header corresponding to the given name', async () => {
app.use('/', (request) => {
expect(getRequestHeader(request, 'accept')).toEqual('application/json')
expect(getRequestHeader(request, 'Accept')).toEqual('application/json')
})
await request.get('/').set('Accept', 'application/json')
})
})

describe('getHeader', () => {
it('can return a value of request header corresponding to the given name', async () => {
app.use('/', (request) => {
expect(getHeader(request, 'accept')).toEqual('application/json')
expect(getHeader(request, 'Accept')).toEqual('application/json')
})
await request.get('/').set('Accept', 'application/json')
})
})

describe('setResponseHeaders', () => {
it('can set multiple values to multiple response headers corresponding to the given object', async () => {
app.use('/', (request) => {
setResponseHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1', 'Nuxt-HTTP-Header-2': 'string-value-2' })
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header-1']).toEqual('string-value-1')
expect(result.headers['nuxt-http-header-2']).toEqual('string-value-2')
})
})

describe('setHeaders', () => {
it('can set multiple values to multiple response headers corresponding to the given object', async () => {
app.use('/', (request) => {
setHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1', 'Nuxt-HTTP-Header-2': 'string-value-2' })
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header-1']).toEqual('string-value-1')
expect(result.headers['nuxt-http-header-2']).toEqual('string-value-2')
})
})

describe('setResponseHeader', () => {
it('can set a string value to response header corresponding to the given name', async () => {
app.use('/', (request) => {
setResponseHeader(request, 'Nuxt-HTTP-Header', 'string-value')
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header']).toEqual('string-value')
})

it('can set a number value to response header corresponding to the given name', async () => {
app.use('/', (request) => {
setResponseHeader(request, 'Nuxt-HTTP-Header', 12345)
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header']).toEqual('12345')
})

it('can set an array value to response header corresponding to the given name', async () => {
app.use('/', (request) => {
setResponseHeader(request, 'Nuxt-HTTP-Header', ['value 1', 'value 2'])
setResponseHeader(request, 'Nuxt-HTTP-Header', ['value 3', 'value 4'])
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header']).toEqual('value 3, value 4')
})
})

describe('setHeader', () => {
it('can set a string value to response header corresponding to the given name', async () => {
app.use('/', (request) => {
setHeader(request, 'Nuxt-HTTP-Header', 'string-value')
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header']).toEqual('string-value')
})

it('can set a number value to response header corresponding to the given name', async () => {
app.use('/', (request) => {
setHeader(request, 'Nuxt-HTTP-Header', 12345)
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header']).toEqual('12345')
})

it('can set an array value to response header corresponding to the given name', async () => {
app.use('/', (request) => {
setHeader(request, 'Nuxt-HTTP-Header', ['value 1', 'value 2'])
setHeader(request, 'Nuxt-HTTP-Header', ['value 3', 'value 4'])
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header']).toEqual('value 3, value 4')
})
})

describe('appendResponseHeaders', () => {
it('can append multiple string values to multiple response header corresponding to the given object', async () => {
app.use('/', (request) => {
appendResponseHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1-1', 'Nuxt-HTTP-Header-2': 'string-value-2-1' })
appendResponseHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1-2', 'Nuxt-HTTP-Header-2': 'string-value-2-2' })
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header-1']).toEqual('string-value-1-1, string-value-1-2')
expect(result.headers['nuxt-http-header-2']).toEqual('string-value-2-1, string-value-2-2')
})
})

describe('appendHeaders', () => {
it('can append multiple string values to multiple response header corresponding to the given object', async () => {
app.use('/', (request) => {
appendHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1-1', 'Nuxt-HTTP-Header-2': 'string-value-2-1' })
appendHeaders(request, { 'Nuxt-HTTP-Header-1': 'string-value-1-2', 'Nuxt-HTTP-Header-2': 'string-value-2-2' })
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header-1']).toEqual('string-value-1-1, string-value-1-2')
expect(result.headers['nuxt-http-header-2']).toEqual('string-value-2-1, string-value-2-2')
})
})

describe('appendResponseHeader', () => {
it('can append a value to response header corresponding to the given name', async () => {
app.use('/', (request) => {
appendResponseHeader(request, 'Nuxt-HTTP-Header', 'value 1')
appendResponseHeader(request, 'Nuxt-HTTP-Header', 'value 2')
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header']).toEqual('value 1, value 2')
})
})

describe('appendHeader', () => {
it('can append a value to response header corresponding to the given name', async () => {
app.use('/', (request) => {
appendHeader(request, 'Nuxt-HTTP-Header', 'value 1')
appendHeader(request, 'Nuxt-HTTP-Header', 'value 2')
})
const result = await request.get('/')
expect(result.headers['nuxt-http-header']).toEqual('value 1, value 2')
})
})
})

0 comments on commit 272f883

Please sign in to comment.