0
0
mirror of https://github.com/honojs/hono.git synced 2024-11-23 17:57:29 +01:00
This commit is contained in:
Yusuke Wada 2024-05-29 16:21:55 +09:00
parent 3d0fbfb7a8
commit 3c0a2a49ee
2 changed files with 283 additions and 0 deletions

View File

@ -0,0 +1,204 @@
import type { ExecutionContext } from '../../context'
import { Hono } from '../../hono'
import { getPath } from '../../utils/url'
import { toHandler } from './index'
const createAnotherApp = (basePath: string = '') => {
return (req: Request, params: unknown) => {
const path = getPath(req)
if (path === `${basePath === '' ? '/' : basePath}`) {
return new Response('AnotherApp')
}
if (path === `${basePath}/hello`) {
return new Response('Hello from AnotherApp')
}
if (path === `${basePath}/header`) {
const message = req.headers.get('x-message')
return new Response(message)
}
if (path === `${basePath}/with-query`) {
const queryStrings = new URL(req.url).searchParams.toString()
return new Response(queryStrings)
}
if (path == `${basePath}/with-params`) {
return new Response(
JSON.stringify({
params,
}),
{
headers: {
'Content-Type': 'application.json',
},
}
)
}
if (path === `${basePath}/path`) {
return new Response(getPath(req))
}
return new Response('Not Found from AnotherApp', {
status: 404,
})
}
}
const testAnotherApp = (app: Hono) => {
it('Should return 200 from AnotherApp - /app', async () => {
const res = await app.request('/app')
expect(res.status).toBe(200)
expect(res.headers.get('x-message')).toBe('Foo')
expect(await res.text()).toBe('AnotherApp')
})
it('Should return 200 from AnotherApp - /app/hello', async () => {
const res = await app.request('/app/hello')
expect(res.status).toBe(200)
expect(res.headers.get('x-message')).toBe('Foo')
expect(await res.text()).toBe('Hello from AnotherApp')
})
it('Should return 200 from AnotherApp - /app/header', async () => {
const res = await app.request('/app/header', {
headers: {
'x-message': 'Message Foo!',
},
})
expect(res.status).toBe(200)
expect(res.headers.get('x-message')).toBe('Foo')
expect(await res.text()).toBe('Message Foo!')
})
it('Should return 404 from AnotherApp - /app/not-found', async () => {
const res = await app.request('/app/not-found')
expect(res.status).toBe(404)
expect(res.headers.get('x-message')).toBe('Foo')
expect(await res.text()).toBe('Not Found from AnotherApp')
})
it('Should return 200 from AnotherApp - /app/with-query?foo=bar&baz-qux', async () => {
const res = await app.request('/app/with-query?foo=bar&baz=qux')
expect(res.status).toBe(200)
expect(await res.text()).toBe('foo=bar&baz=qux')
})
it('Should return 200 from AnotherApp - /app/with-params', async () => {
const res = await app.request('/app/with-params')
expect(res.status).toBe(200)
expect(await res.json()).toEqual({
params: 'params',
})
})
}
describe('Basic', () => {
const anotherApp = createAnotherApp('/app')
const app = new Hono()
app.use('*', async (c, next) => {
await next()
c.header('x-message', 'Foo')
})
app.get('/', (c) => c.text('Hono'))
app.all(
'/app/*',
toHandler(anotherApp, {
optionHandler: () => 'params',
})
)
it('Should return 200 from Hono app', async () => {
const res = await app.request('/')
expect(res.status).toBe(200)
expect(res.headers.get('x-message')).toBe('Foo')
expect(await res.text()).toBe('Hono')
})
testAnotherApp(app)
it('Should return 200 from AnotherApp - /app/path', async () => {
const res = await app.request('/app/path')
expect(res.status).toBe(200)
expect(await res.text()).toBe('/app/path')
})
})
describe('With basePath', () => {
const anotherApp = createAnotherApp()
const app = new Hono()
app.use('*', async (c, next) => {
await next()
c.header('x-message', 'Foo')
})
app.all(
'/app/*',
toHandler(anotherApp, {
optionHandler: () => 'params',
basePath: '/app',
})
)
testAnotherApp(app)
it('Should return 200 from AnotherApp - /app/path', async () => {
const res = await app.request('/app/path')
expect(res.status).toBe(200)
expect(await res.text()).toBe('/path')
})
})
describe('With fetch', () => {
const anotherApp = async (req: Request, env: {}, executionContext: ExecutionContext) => {
const path = getPath(req)
if (path === '/') {
return new Response(
JSON.stringify({
env,
executionContext,
}),
{
headers: {
'Content-Type': 'application/json',
},
}
)
}
return new Response('Not Found from AnotherApp', {
status: 404,
})
}
const app = new Hono()
app.all(
'/another-app/*',
toHandler(anotherApp, {
basePath: '/another-app',
})
)
it('Should handle Env and ExecuteContext', async () => {
const request = new Request('http://localhost/another-app')
const res = await app.fetch(
request,
{
TOKEN: 'foo',
},
{
// Force mocking!
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
waitUntil: 'waitUntil',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
passThroughOnException: 'passThroughOnException',
}
)
expect(res.status).toBe(200)
expect(await res.json()).toEqual({
env: {
TOKEN: 'foo',
},
executionContext: {
waitUntil: 'waitUntil',
passThroughOnException: 'passThroughOnException',
},
})
})
})

View File

@ -0,0 +1,79 @@
/**
* @module
* Mounting Helper for Hono.
*/
import type { Context, ExecutionContext } from '../../context'
import type { MiddlewareHandler } from '../../types'
import { getQueryStrings, mergePath } from '../../utils/url'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Application = (request: Request, ...args: any) => Response | Promise<Response>
type OptionHandler = (c: Context) => unknown
type ToHandlerOptions = {
optionHandler?: OptionHandler
basePath?: string
}
/**
* @param {Application} application - The application handler to be used.
* @param {ToHandlerOptions} [options] - Optional configurations for the handler.
* @param {OptionHandler} [options.optionHandler] - A function to handle additional options.
* @param {string} [options.basePath] - The base path to be used for the application.
* @returns {MiddlewareHandler} The middleware handler function.
*
* @example
* ```ts
* const app = new Hono()
*
* app.all(
* '/another-app/*',
* toHandler(anotherApp.fetch, {
* basePath: '/another-app',
* })
* )
* ```
*/
export const toHandler = (
application: Application,
options?: ToHandlerOptions
): MiddlewareHandler => {
return async (c, next) => {
let executionContext: ExecutionContext | undefined = undefined
try {
executionContext = c.executionCtx
} catch {} // Do nothing
let applicationOptions: unknown[] = []
if (options?.optionHandler) {
const result = options.optionHandler(c)
applicationOptions = Array.isArray(result) ? result : [result]
} else {
applicationOptions = [c.env, executionContext]
}
let path: string
if (options?.basePath) {
const basePath = mergePath('/', options.basePath)
const regexp = new RegExp(`^${basePath}`)
path = c.req.path.replace(regexp, '')
if (path === '') {
path = '/'
}
} else {
path = c.req.path
}
const queryStrings = getQueryStrings(c.req.url)
const res = await application(
new Request(new URL(path + queryStrings, c.req.url), c.req.raw),
...applicationOptions
)
if (res) {
return res
}
await next()
}
}