mirror of
https://github.com/honojs/hono.git
synced 2024-11-23 17:57:29 +01:00
WIP
This commit is contained in:
parent
3d0fbfb7a8
commit
3c0a2a49ee
204
src/helper/mounting/index.test.ts
Normal file
204
src/helper/mounting/index.test.ts
Normal 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',
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
79
src/helper/mounting/index.ts
Normal file
79
src/helper/mounting/index.ts
Normal 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()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user