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