Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: unjs/h3
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.7.13
Choose a base ref
...
head repository: unjs/h3
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.7.14
Choose a head ref
  • 6 commits
  • 9 files changed
  • 5 contributors

Commits on Aug 1, 2022

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    56bfe0a View commit details

Commits on Aug 3, 2022

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    272f883 View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    4b83bdf View commit details

Commits on Aug 5, 2022

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    7e42722 View commit details

Commits on Aug 8, 2022

  1. chore(deps): update pnpm to v7.9.0 (#160)

    Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
    renovate[bot] authored Aug 8, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    90e4e93 View commit details
  2. chore(release): 0.7.14

    pi0 committed Aug 8, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    a8fa857 View commit details
Showing with 373 additions and 17 deletions.
  1. +8 −0 CHANGELOG.md
  2. +16 −1 README.md
  3. +2 −2 package.json
  4. +9 −3 src/utils/body.ts
  5. +10 −4 src/utils/cookie.ts
  6. +37 −5 src/utils/request.ts
  7. +30 −1 src/utils/response.ts
  8. +190 −0 test/header.test.ts
  9. +71 −1 test/router.test.ts
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,14 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [0.7.14](https://github.com/unjs/h3/compare/v0.7.13...v0.7.14) (2022-08-08)


### Features

* add utilities for http headers ([#157](https://github.com/unjs/h3/issues/157)) ([272f883](https://github.com/unjs/h3/commit/272f883c3e6413a632e871de3a796d62e6c5da43))
* add utility for router params ([#120](https://github.com/unjs/h3/issues/120)) ([#158](https://github.com/unjs/h3/issues/158)) ([4b83bdf](https://github.com/unjs/h3/commit/4b83bdf83b94da3f66018378d39c5cc24afdf43f))

### [0.7.13](https://github.com/unjs/h3/compare/v0.7.12...v0.7.13) (2022-08-01)


17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -112,6 +112,8 @@ app.use((req, res, next) => { req.setHeader('X-Foo', 'bar'); next() })

## Utilities

### Built-in

Instead of adding helpers to `req` and `res`, h3 exposes them as composable utilities.

- `useRawBody(req, encoding?)`
@@ -121,9 +123,15 @@ Instead of adding helpers to `req` and `res`, h3 exposes them as composable util
- `setCookie(res, name, value, opts?)`
- `deleteCookie(res, name, opts?)`
- `useQuery(req)`
- `getRouterParams(event)`
- `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)`
@@ -134,6 +142,13 @@ Instead of adding helpers to `req` and `res`, h3 exposes them as composable util

👉 You can learn more about usage in [JSDocs Documentation](https://www.jsdocs.io/package/h3#package-functions).

### Add-ons

More composable utilities can be found in community packages.

- `validateBody(event, schema)` from [h3-typebox](https://github.com/kevinmarrec/h3-typebox)
- `validateQuery(event, schema)` from [h3-typebox](https://github.com/kevinmarrec/h3-typebox)

## How it works?

Using `createApp`, it returns a standard `(req, res)` handler function and internally an array called middleware stack. using`use()` method we can add an item to this internal stack.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "h3",
"version": "0.7.13",
"version": "0.7.14",
"description": "Tiny JavaScript Server",
"repository": "unjs/h3",
"license": "MIT",
@@ -54,5 +54,5 @@
"unbuild": "latest",
"vitest": "latest"
},
"packageManager": "pnpm@7.8.0"
"packageManager": "pnpm@7.9.0"
}
12 changes: 9 additions & 3 deletions src/utils/body.ts
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ const PayloadMethods: HTTPMethod[] = ['PATCH', 'POST', 'PUT', 'DELETE']
*
* @return {String|Buffer} Encoded raw string or raw Buffer of the body
*/
export function useRawBody (event: CompatibilityEvent, encoding: Encoding = 'utf-8'): Encoding extends false ? Buffer : Promise<string | Buffer> {
export function readRawBody (event: CompatibilityEvent, encoding: Encoding = 'utf-8'): Encoding extends false ? Buffer : Promise<string | Buffer> {
// Ensure using correct HTTP method before attempt to read payload
assertMethod(event, PayloadMethods)

@@ -40,6 +40,9 @@ export function useRawBody (event: CompatibilityEvent, encoding: Encoding = 'utf
return encoding ? promise.then(buff => buff.toString(encoding)) : promise
}

/** @deprecated Use `h3.readRawBody` */
export const useRawBody = readRawBody

/**
* Reads request body and try to safely parse using [destr](https://github.com/unjs/destr)
* @param event {CompatibilityEvent} H3 event or req passed by h3 handler
@@ -51,13 +54,13 @@ export function useRawBody (event: CompatibilityEvent, encoding: Encoding = 'utf
* const body = await useBody(req)
* ```
*/
export async function useBody<T=any> (event: CompatibilityEvent): Promise<T> {
export async function readBody<T=any> (event: CompatibilityEvent): Promise<T> {
if (ParsedBodySymbol in event.req) {
return (event.req as any)[ParsedBodySymbol]
}

// TODO: Handle buffer
const body = await useRawBody(event) as string
const body = await readRawBody(event) as string

if (event.req.headers['content-type'] === 'application/x-www-form-urlencoded') {
const parsedForm = Object.fromEntries(new URLSearchParams(body))
@@ -68,3 +71,6 @@ export async function useBody<T=any> (event: CompatibilityEvent): Promise<T> {
(event.req as any)[ParsedBodySymbol] = json
return json
}

/** @deprecated Use `h3.readBody` */
export const useBody = readBody
14 changes: 10 additions & 4 deletions src/utils/cookie.ts
Original file line number Diff line number Diff line change
@@ -8,13 +8,16 @@ import { appendHeader } from './response'
* @param event {CompatibilityEvent} H3 event or req passed by h3 handler
* @returns Object of cookie name-value pairs
* ```ts
* const cookies = useCookies(req)
* const cookies = parseCookies(event)
* ```
*/
export function useCookies (event: CompatibilityEvent): Record<string, string> {
export function parseCookies (event: CompatibilityEvent): Record<string, string> {
return parse(event.req.headers.cookie || '')
}

/** @deprecated Use `h3.parseCookies` */
export const useCookies = parseCookies

/**
* Get a cookie value by name.
* @param event {CompatibilityEvent} H3 event or req passed by h3 handler
@@ -24,10 +27,13 @@ export function useCookies (event: CompatibilityEvent): Record<string, string> {
* const authorization = useCookie(request, 'Authorization')
* ```
*/
export function useCookie (event: CompatibilityEvent, name: string): string | undefined {
return useCookies(event)[name]
export function getCookie (event: CompatibilityEvent, name: string): string | undefined {
return parseCookies(event)[name]
}

/** @deprecated Use `h3.getCookie` */
export const useCookie = getCookie

/**
* Set a cookie value by name.
* @param event {CompatibilityEvent} H3 event or res passed by h3 handler
42 changes: 37 additions & 5 deletions src/utils/request.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
import { getQuery } from 'ufo'
import { getQuery as _getQuery } from 'ufo'
import { createError } from '../error'
import type { HTTPMethod } from '../types'
import type { CompatibilityEvent } from '../event'

export function useQuery (event: CompatibilityEvent) {
return getQuery(event.req.url || '')
export function getQuery (event: CompatibilityEvent) {
return _getQuery(event.req.url || '')
}

export function useMethod (event: CompatibilityEvent, defaultMethod: HTTPMethod = 'GET'): HTTPMethod {
/** @deprecated Use `h3.getQuery` */
export const useQuery = getQuery

export function getRouterParams (event: CompatibilityEvent): CompatibilityEvent['context'] {
// Fallback object needs to be returned in case router is not used (#149)
return event.context.params || {}
}

export function getRouterParam (event: CompatibilityEvent, name: string): CompatibilityEvent['context'][string] {
const params = getRouterParams(event)

return params[name]
}

export function getMethod (event: CompatibilityEvent, defaultMethod: HTTPMethod = 'GET'): HTTPMethod {
return (event.req.method || defaultMethod).toUpperCase() as HTTPMethod
}

/** @deprecated Use `h3.getMethod` */
export const useMethod = getMethod

export function isMethod (event: CompatibilityEvent, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean) {
const method = useMethod(event)
const method = getMethod(event)

if (allowHead && method === 'HEAD') {
return true
@@ -37,3 +54,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'
@@ -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) {
@@ -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'
}
Loading