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

feat: update visibility (#164)

This commit is contained in:
Yusuke Wada 2022-04-21 21:55:01 +09:00 committed by GitHub
parent 1a30e37dfa
commit 3d064d0559
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 75 additions and 101 deletions

View File

@ -25,7 +25,7 @@ export class Context<RequestParamKeyType = string> {
req: Request<RequestParamKeyType>,
opts?: { res: Response; env: Env; event: FetchEvent }
) {
this.req = req
this.req = this.initRequest(req)
if (opts) {
this.res = opts.res
this.env = opts.env
@ -34,14 +34,18 @@ export class Context<RequestParamKeyType = string> {
this._headers = {}
}
private initRequest<T>(req: Request<T>): Request<T> {
req.header = (name: string): string => {
return req.headers.get(name)
}
req.query = (key: string): string => {
const url = new URL(req.url)
return url.searchParams.get(key)
}
return req
}
header(name: string, value: string): void {
/*
XXX:
app.use('*', (c, next) => {
next()
c.header('foo', 'bar') // => c.res.headers.set(...)
})
*/
if (this.res) {
this.res.headers.set(name, value)
}
@ -101,7 +105,7 @@ export class Context<RequestParamKeyType = string> {
json(object: object, status: StatusCode = this._status, headers: Headers = {}): Response {
if (typeof object !== 'object') {
throw new TypeError('json method arg must be a object!')
throw new TypeError('json method arg must be an object!')
}
const body = this._pretty
? JSON.stringify(object, null, this._prettySpace)

View File

@ -11,7 +11,6 @@ declare global {
param: (key: ParamKeyType) => string
query: (key: string) => string
header: (name: string) => string
// TODO: do not use `any`
parsedBody: any
}
}
@ -64,11 +63,11 @@ export class Hono extends defineDynamicClass(
'patch',
'all'
) {
routerClass: { new (): Router<any> } = TrieRouter
strict: boolean = true // strict routing - default is true
router: Router<Handler>
middlewareRouters: Router<MiddlewareHandler>[]
tempPath: string
readonly routerClass: { new (): Router<any> } = TrieRouter
readonly strict: boolean = true // strict routing - default is true
private router: Router<Handler>
private middlewareRouters: Router<MiddlewareHandler>[]
private tempPath: string
constructor(init: Partial<Pick<Hono, 'routerClass' | 'strict'>> = {}) {
super()
@ -137,7 +136,7 @@ export class Hono extends defineDynamicClass(
return this.router.match(method, path)
}
async dispatch(request: Request, env?: Env, event?: FetchEvent): Promise<Response> {
private async dispatch(request: Request, env?: Env, event?: FetchEvent): Promise<Response> {
const path = getPathFromURL(request.url, { strict: this.strict })
const method = request.method
@ -147,13 +146,6 @@ export class Hono extends defineDynamicClass(
request.param = (key: string): string => {
if (result) return result.params[key]
}
request.header = (name: string): string => {
return request.headers.get(name)
}
request.query = (key: string): string => {
const url = new URL(c.req.url)
return url.searchParams.get(key)
}
const handler = result ? result.handler : this.notFoundHandler
@ -192,12 +184,12 @@ export class Hono extends defineDynamicClass(
return this.dispatch(request, env, event)
}
request(input: RequestInfo, requestInit?: RequestInit) {
const req = new Request(input, requestInit)
request(input: RequestInfo, requestInit?: RequestInit): Promise<Response> {
const req = input instanceof Request ? input : new Request(input, requestInit)
return this.dispatch(req)
}
fire() {
fire(): void {
addEventListener('fetch', (event: FetchEvent): void => {
event.respondWith(this.handleEvent(event))
})

View File

@ -67,42 +67,42 @@ describe('Basic Auth by Middleware', () => {
app.get('/auth-multi/*', () => new Response('auth'))
app.get('/auth-override-func/*', () => new Response('auth'))
it('Unauthorized', async () => {
it('Should not authorize', async () => {
const req = new Request('http://localhost/auth/a')
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res).not.toBeNull()
expect(res.status).toBe(401)
expect(await res.text()).toBe('Unauthorized')
})
it('Authorizated', async () => {
it('Should authorize', async () => {
const credential = Buffer.from(username + ':' + password).toString('base64')
const req = new Request('http://localhost/auth/a')
req.headers.set('Authorization', `Basic ${credential}`)
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(await res.text()).toBe('auth')
})
it('Authorizated Unicode', async () => {
it('Should authorize Unicode', async () => {
const credential = Buffer.from(username + ':' + unicodePassword).toString('base64')
const req = new Request('http://localhost/auth-unicode/a')
req.headers.set('Authorization', `Basic ${credential}`)
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(await res.text()).toBe('auth')
})
it('Authorizated multiple users', async () => {
it('Should authorize multiple users', async () => {
let credential = Buffer.from(usernameB + ':' + passwordB).toString('base64')
let req = new Request('http://localhost/auth-multi/b')
req.headers.set('Authorization', `Basic ${credential}`)
let res = await app.dispatch(req)
let res = await app.request(req)
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(await res.text()).toBe('auth')
@ -110,18 +110,18 @@ describe('Basic Auth by Middleware', () => {
credential = Buffer.from(usernameC + ':' + passwordC).toString('base64')
req = new Request('http://localhost/auth-multi/c')
req.headers.set('Authorization', `Basic ${credential}`)
res = await app.dispatch(req)
res = await app.request(req)
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(await res.text()).toBe('auth')
})
it('should authorize with sha256 function override', async () => {
it('Should authorize with sha256 function override', async () => {
const credential = Buffer.from(username + ':' + password).toString('base64')
const req = new Request('http://localhost/auth-override-func/a')
req.headers.set('Authorization', `Basic ${credential}`)
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(await res.text()).toBe('auth')

View File

@ -22,7 +22,7 @@ describe('Parse Body Middleware', () => {
body: JSON.stringify(payload),
headers: new Headers({ 'Content-Type': 'application/json' }),
})
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(req.parsedBody).toEqual(payload)
@ -36,7 +36,7 @@ describe('Parse Body Middleware', () => {
body: 'hello',
headers: new Headers({ 'Content-Type': 'application/text' }),
})
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(req.parsedBody).toEqual(payload)
@ -53,7 +53,7 @@ describe('Parse Body Middleware', () => {
'Content-Type': 'application/x-www-form-urlencoded',
},
})
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(req.parsedBody).toEqual({ message: 'hello' })

View File

@ -18,7 +18,7 @@ describe('Cookie Middleware', () => {
const req = new Request('http://localhost/cookie')
const cookieString = 'yummy_cookie=choco; tasty_cookie = strawberry '
req.headers.set('Cookie', cookieString)
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res.headers.get('Yummy-Cookie')).toBe('choco')
expect(res.headers.get('Tasty-Cookie')).toBe('strawberry')
@ -32,8 +32,7 @@ describe('Cookie Middleware', () => {
})
it('Set cookie on c.cookie', async () => {
const req = new Request('http://localhost/set-cookie')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/set-cookie')
expect(res.status).toBe(200)
const header = res.headers.get('Set-Cookie')
expect(header).toBe('delicious_cookie=macha')
@ -55,8 +54,7 @@ describe('Cookie Middleware', () => {
})
it('Complex pattern', async () => {
const req = new Request('http://localhost/set-cookie-complex')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/set-cookie-complex')
expect(res.status).toBe(200)
const header = res.headers.get('Set-Cookie')
expect(header).toBe(

View File

@ -25,8 +25,7 @@ describe('CORS by Middleware', () => {
})
it('GET default', async () => {
const req = new Request('http://localhost/api/abc')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/api/abc')
expect(res.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(res.headers.get('Vary')).toBeNull()
@ -35,7 +34,7 @@ describe('CORS by Middleware', () => {
it('Preflight default', async () => {
const req = new Request('https://localhost/api/abc', { method: 'OPTIONS' })
req.headers.append('Access-Control-Request-Headers', 'X-PINGOTHER, Content-Type')
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res.status).toBe(204)
expect(res.headers.get('Access-Control-Allow-Methods').split(',')[0]).toBe('GET')
@ -47,7 +46,7 @@ describe('CORS by Middleware', () => {
it('Preflight with options', async () => {
const req = new Request('https://localhost/api2/abc', { method: 'OPTIONS' })
const res = await app.dispatch(req)
const res = await app.request(req)
expect(res.headers.get('Access-Control-Allow-Origin')).toBe('http://example.com')
expect(res.headers.get('Vary').split(/\s*,\s*/)).toEqual(expect.arrayContaining(['Origin']))

View File

@ -17,43 +17,34 @@ describe('Etag Middleware', () => {
return c.text('Hono is cool')
})
it('should return etag header', async () => {
let req = new Request('http://localhost/etag/abc')
let res = await app.dispatch(req)
it('Should return etag header', async () => {
let res = await app.request('http://localhost/etag/abc')
expect(res.headers.get('ETag')).not.toBeFalsy()
expect(res.headers.get('ETag')).toBe('"4e32298b1cb4edc595237405e5b696e105c2399a"')
req = new Request('http://localhost/etag/def')
res = await app.dispatch(req)
res = await app.request('http://localhost/etag/def')
expect(res.headers.get('ETag')).not.toBeFalsy()
expect(res.headers.get('ETag')).toBe('"c1d44ff03aff1372856c281854f454e2e1d15b7c"')
})
it('should return etag header - weak', async () => {
const req = new Request('http://localhost/etag-weak/abc')
const res = await app.dispatch(req)
it('Should return etag header - weak', async () => {
const res = await app.request('http://localhost/etag-weak/abc')
expect(res.headers.get('ETag')).not.toBeFalsy()
expect(res.headers.get('ETag')).toBe('W/"4e32298b1cb4edc595237405e5b696e105c2399a"')
})
it('should return 304 response', async () => {
let req = new Request('http://localhost/etag/abc')
let res = await app.dispatch(req)
it('Should return 304 response', async () => {
let res = await app.request('http://localhost/etag/abc')
expect(res.status).toBe(200)
expect(res.headers.get('ETag')).not.toBeFalsy()
const etag = res.headers.get('Etag')
req = new Request('http://localhost/etag/abc', {
const req = new Request('http://localhost/etag/abc', {
headers: {
'If-None-Match': etag,
},
})
res = await app.dispatch(req)
res = await app.request(req)
expect(res.status).toBe(304)
expect(await res.text()).toBe('')
})

View File

@ -18,8 +18,7 @@ describe('Logger by Middleware', () => {
app.get('/empty', (c) => c.text(''))
it('Log status 200 with empty body', async () => {
const req = new Request('http://localhost/empty')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/empty')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(log.startsWith(' --> GET /empty \x1b[32m200\x1b[0m')).toBe(true)
@ -27,8 +26,7 @@ describe('Logger by Middleware', () => {
})
it('Log status 200 with small body', async () => {
const req = new Request('http://localhost/short')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/short')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(log.startsWith(' --> GET /short \x1b[32m200\x1b[0m')).toBe(true)
@ -36,8 +34,7 @@ describe('Logger by Middleware', () => {
})
it('Log status 200 with big body', async () => {
const req = new Request('http://localhost/long')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/long')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(log.startsWith(' --> GET /long \x1b[32m200\x1b[0m')).toBe(true)
@ -49,9 +46,7 @@ describe('Logger by Middleware', () => {
app.all('*', (c) => {
return c.text(msg, 404)
})
const req = new Request('http://localhost/notfound')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/notfound')
expect(res).not.toBeNull()
expect(res.status).toBe(404)
expect(log.startsWith(' --> GET /notfound \x1b[33m404\x1b[0m')).toBe(true)

View File

@ -45,15 +45,13 @@ describe('Mustache by Middleware', () => {
})
it('Mustache template rendering', async () => {
const req = new Request('http://localhost/foo')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/foo')
expect(res.status).toBe(200)
expect(await res.text()).toBe('<html><body>Title: Hono!</body></html>')
})
it('Mustache template rendering with root', async () => {
const req = new Request('http://localhost/bar')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/bar')
expect(res.status).toBe(200)
expect(await res.text()).toBe('<h1>With Root</h1>')
})

View File

@ -5,11 +5,10 @@ describe('Powered by Middleware', () => {
const app = new Hono()
app.use('*', poweredBy())
app.get('/', () => new Response('root'))
app.get('/', (c) => c.text('root'))
it('Response headers include X-Powered-By', async () => {
const req = new Request('http://localhost/')
const res = await app.dispatch(req)
it('Should return with X-Powered-By header', async () => {
const res = await app.request('http://localhost/')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(res.headers.get('X-Powered-By')).toBe('Hono')

View File

@ -10,8 +10,7 @@ describe('JSON pretty by Middleware', () => {
it('Should return pretty JSON output', async () => {
app.use('*', prettyJSON())
const req = new Request('http://localhost/?pretty')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/?pretty')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(await res.text()).toBe(`{
@ -21,8 +20,7 @@ describe('JSON pretty by Middleware', () => {
it('Should return pretty JSON output with 4 spaces', async () => {
app.use('*', prettyJSON({ space: 4 }))
const req = new Request('http://localhost/?pretty')
const res = await app.dispatch(req)
const res = await app.request('http://localhost/?pretty')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(await res.text()).toBe(`{

View File

@ -26,40 +26,40 @@ Object.assign(global, {
describe('ServeStatic Middleware', () => {
const app = new Hono()
app.use('/static/*', serveStatic({ root: './assets' }))
app.use('/static-no-root/*', serveStatic())
it('Serve static files', async () => {
let req = new Request('http://localhost/static/plain.txt')
let res = await app.dispatch(req)
it('Should return plain.txt', async () => {
const res = await app.request('http://localhost/static/plain.txt')
expect(res.status).toBe(200)
expect(await res.text()).toBe('This is plain.txt')
expect(res.headers.get('Content-Type')).toBe('text/plain; charset=utf-8')
expect(res.headers.get('Content-Length')).toBe('17')
})
req = new Request('http://localhost/static/hono.html')
res = await app.dispatch(req)
it('Should return hono.html', async () => {
const res = await app.request('http://localhost/static/hono.html')
expect(res.status).toBe(200)
expect(await res.text()).toBe('<h1>Hono!</h1>')
expect(res.headers.get('Content-Type')).toBe('text/html; charset=utf-8')
expect(res.headers.get('Content-Length')).toBe('14')
})
req = new Request('http://localhost/static/not-found.html')
res = await app.dispatch(req)
it('Should return 404 response', async () => {
const res = await app.request('http://localhost/static/not-found.html')
expect(res.status).toBe(404)
})
req = new Request('http://localhost/static-no-root/plain.txt')
res = await app.dispatch(req)
it('Should return plan.txt', async () => {
const res = await app.request('http://localhost/static-no-root/plain.txt')
expect(res.status).toBe(200)
expect(await res.text()).toBe('That is plain.txt')
expect(res.headers.get('Content-Type')).toBe('text/plain; charset=utf-8')
expect(res.headers.get('Content-Length')).toBe('17')
})
it('Serve index.html', async () => {
const req = new Request('http://localhost/static/top')
const res = await app.dispatch(req)
it('Should return index.html', async () => {
const res = await app.request('http://localhost/static/top')
expect(res.status).toBe(200)
expect(await res.text()).toBe('<h1>Top</h1>')
expect(res.headers.get('Content-Type')).toBe('text/html; charset=utf-8')