diff --git a/README.md b/README.md index bbb63867..784f23d8 100644 --- a/README.md +++ b/README.md @@ -214,9 +214,9 @@ H3 has a concept of composable utilities that accept `event` (from `eventHandler - `getQuery(event)` - `getValidatedQuery(event, validate)` -- `getRouterParams(event)` -- `getValidatedRouterParams(event, validate)` -- `getRouterParam(event, name)` +- `getRouterParams(event, { decode? })` +- `getRouterParam(event, name, { decode? })` +- `getValidatedRouterParams(event, validate, { decode? })` - `getMethod(event, default?)` - `isMethod(event, expected, allowHead?)` - `assertMethod(event, expected, allowHead?)` diff --git a/src/utils/request.ts b/src/utils/request.ts index 28785e8e..f97c790b 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,4 +1,4 @@ -import { getQuery as _getQuery } from "ufo"; +import { getQuery as _getQuery, decode as decodeURI } from "ufo"; import { createError } from "../error"; import type { HTTPHeaderName, @@ -29,17 +29,30 @@ export function getValidatedQuery< export function getRouterParams( event: H3Event, + opts: { decode?: boolean } = {}, ): NonNullable { // Fallback object needs to be returned in case router is not used (#149) - return event.context.params || {}; + let params = event.context.params || {}; + if (opts.decode) { + params = { ...params }; + for (const key in params) { + params[key] = decodeURI(params[key]); + } + } + + return params; } export function getValidatedRouterParams< T, Event extends H3Event = H3Event, _T = InferEventInput<"routerParams", Event, T>, ->(event: Event, validate: ValidateFunction<_T>): Promise<_T> { - const routerParams = getRouterParams(event); +>( + event: Event, + validate: ValidateFunction<_T>, + opts: { decode?: boolean } = {}, +): Promise<_T> { + const routerParams = getRouterParams(event, opts); return validateData(routerParams, validate); } @@ -47,8 +60,9 @@ export function getValidatedRouterParams< export function getRouterParam( event: H3Event, name: string, + opts: { decode?: boolean } = {}, ): string | undefined { - const params = getRouterParams(event); + const params = getRouterParams(event, opts); return params[name]; } diff --git a/test/router.test.ts b/test/router.test.ts index 65063555..f748b90e 100644 --- a/test/router.test.ts +++ b/test/router.test.ts @@ -189,6 +189,22 @@ describe("getRouterParams", () => { expect(result.text).toBe("200"); }); + + it("can decode router params", async () => { + const router = createRouter().get( + "/test/params/:name", + eventHandler((event) => { + expect(getRouterParams(event, { decode: true })).toMatchObject({ + name: "string with space", + }); + return "200"; + }), + ); + app.use(router); + const result = await request.get("/test/params/string with space"); + + expect(result.text).toBe("200"); + }); }); describe("without router", () => { @@ -230,6 +246,22 @@ describe("getRouterParam", () => { expect(result.text).toBe("200"); }); + + it("can decode a value of router params corresponding to the given name", async () => { + const router = createRouter().get( + "/test/params/:name", + eventHandler((event) => { + expect(getRouterParam(event, "name", { decode: true })).toEqual( + "string with space", + ); + return "200"; + }), + ); + app.use(router); + const result = await request.get("/test/params/string with space"); + + expect(result.text).toBe("200"); + }); }); describe("without router", () => {