0
0
mirror of https://github.com/honojs/hono.git synced 2024-12-01 11:51:01 +01:00
hono/deno_dist/request.ts

225 lines
5.7 KiB
TypeScript
Raw Normal View History

import type { InputToData, InputToTypeData, ValidationTypes } from './types.ts'
2022-07-12 16:25:47 +02:00
import { parseBody } from './utils/body.ts'
import type { BodyData } from './utils/body.ts'
2022-07-10 17:17:29 +02:00
import type { Cookie } from './utils/cookie.ts'
import { parse } from './utils/cookie.ts'
import { mergeObjects } from './utils/object.ts'
import type { UnionToIntersection } from './utils/types.ts'
import { getQueryStringFromURL, getQueryParam, getQueryParams } from './utils/url.ts'
2022-07-10 17:17:29 +02:00
2023-01-22 06:28:13 +01:00
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type ParamKeyName<NameWithPattern> = NameWithPattern extends `${infer Name}{${infer _Pattern}`
? Name
: NameWithPattern
type ParamKey<Component> = Component extends `:${infer NameWithPattern}`
? ParamKeyName<NameWithPattern>
: never
type ParamKeys<Path> = Path extends `${infer Component}/${infer Rest}`
? ParamKey<Component> | ParamKeys<Rest>
: ParamKey<Path>
2022-07-10 17:17:29 +02:00
type RemoveQuestion<T> = T extends `${infer R}?` ? R : T
2023-01-22 06:28:13 +01:00
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type UndefinedIfHavingQuestion<T> = T extends `${infer _}?` ? string | undefined : string
2023-01-22 06:28:13 +01:00
type ParamKeyToRecord<T extends string> = T extends `${infer R}?`
? Record<R, string | undefined>
: Record<T, string>
export class HonoRequest<Path extends string = '/', Input = {}> {
raw: Request
2022-07-02 08:09:45 +02:00
private paramData: Record<string, string> | undefined
private headerData: Record<string, string> | undefined
private bodyData: BodyData | undefined
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private jsonData: Promise<any> | undefined
private validatedData: { [K in keyof ValidationTypes]?: {} }
private queryIndex: number
2023-01-10 13:24:21 +01:00
constructor(
request: Request,
paramData?: Record<string, string> | undefined,
queryIndex: number = -1
2023-01-10 13:24:21 +01:00
) {
this.raw = request
this.paramData = paramData
2023-01-10 13:24:21 +01:00
this.queryIndex = queryIndex
this.validatedData = {}
2022-07-02 08:09:45 +02:00
}
2023-01-22 06:28:13 +01:00
param(key: RemoveQuestion<ParamKeys<Path>>): UndefinedIfHavingQuestion<ParamKeys<Path>>
param(): UnionToIntersection<ParamKeyToRecord<ParamKeys<Path>>>
param(key?: string): unknown {
2022-07-02 08:09:45 +02:00
if (this.paramData) {
if (key) {
const param = this.paramData[key]
return param ? (/\%/.test(param) ? decodeURIComponent(param) : param) : undefined
2022-07-02 08:09:45 +02:00
} else {
const decoded: Record<string, string> = {}
for (const [key, value] of Object.entries(this.paramData)) {
if (value && typeof value === 'string') {
decoded[key] = /\%/.test(value) ? decodeURIComponent(value) : value
}
}
return decoded
2022-07-02 08:09:45 +02:00
}
}
return null
}
2022-07-02 08:09:45 +02:00
query(key: string): string
query(): Record<string, string>
query(key?: string) {
2023-01-10 13:24:21 +01:00
const queryString = getQueryStringFromURL(this.url, this.queryIndex)
return getQueryParam(queryString, key)
}
2022-07-02 08:09:45 +02:00
queries(key: string): string[]
queries(): Record<string, string[]>
queries(key?: string) {
2023-01-10 13:24:21 +01:00
const queryString = getQueryStringFromURL(this.url, this.queryIndex)
return getQueryParams(queryString, key)
}
header(name: string): string
header(): Record<string, string>
header(name?: string) {
if (!this.headerData) {
this.headerData = {}
this.raw.headers.forEach((value, key) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.headerData![key] = value
})
}
if (name) {
return this.headerData[name.toLowerCase()]
} else {
return this.headerData
}
}
2022-07-10 17:17:29 +02:00
cookie(key: string): string | undefined
cookie(): Cookie
cookie(key?: string) {
const cookie = this.raw.headers.get('Cookie')
if (!cookie) return
2022-07-10 17:17:29 +02:00
const obj = parse(cookie)
if (key) {
const value = obj[key]
return value
} else {
return obj
}
}
2022-07-12 16:25:47 +02:00
async parseBody(): Promise<BodyData> {
// Cache the parsed body
let body: BodyData
if (!this.bodyData) {
body = await parseBody(this.raw)
this.bodyData = body
} else {
body = this.bodyData
2022-07-12 16:25:47 +02:00
}
return body
}
async json<JSONData = unknown>() {
// Cache the JSON body
let jsonData: Promise<Partial<JSONData>>
if (!this.jsonData) {
jsonData = this.raw.json()
this.jsonData = jsonData
} else {
jsonData = this.jsonData
}
return jsonData
}
async text() {
return this.raw.text()
}
async arrayBuffer() {
return this.raw.arrayBuffer()
}
async blob() {
return this.raw.blob()
}
async formData() {
return this.raw.formData()
}
addValidatedData(type: keyof ValidationTypes, data: {}) {
const storedData = this.validatedData[type] || {}
const merged = mergeObjects(storedData, data)
this.validatedData[type] = merged
}
valid(): InputToData<Input>
valid<T extends keyof ValidationTypes>(type: T): InputToTypeData<T, Input>
valid<T extends keyof ValidationTypes>(type?: T) {
if (type) {
const data = this.validatedData[type]
return data
} else {
let data: Record<string, unknown> = {}
for (const v of Object.values(this.validatedData)) {
data = mergeObjects(data, v)
}
return data
}
}
get url() {
return this.raw.url
}
get method() {
return this.raw.method
}
get headers() {
return this.raw.headers
}
get redirect() {
return this.raw.redirect
}
get body() {
return this.raw.body
}
get bodyUsed() {
return this.raw.bodyUsed
}
get cache() {
return this.raw.cache
}
get credentials() {
return this.raw.credentials
}
get integrity() {
return this.raw.integrity
}
get keepalive() {
return this.raw.keepalive
}
get mode() {
return this.raw.mode
}
get referrer() {
return this.raw.referrer
}
get refererPolicy() {
return this.raw.referrerPolicy
}
get signal() {
return this.raw.signal
}
2022-07-02 08:09:45 +02:00
}