Skip to content

Commit

Permalink
feat: add support for Response in component routing (#266)
Browse files Browse the repository at this point in the history
  • Loading branch information
IKatsuba authored Feb 24, 2025
1 parent ba7279d commit a9a1af4
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 2 deletions.
5 changes: 5 additions & 0 deletions mocks/app-function/routes/api-response.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default function ApiResponse() {
return new Response(JSON.stringify({ message: 'API Response' }), {
headers: { 'Content-Type': 'application/json' },
})
}
4 changes: 4 additions & 0 deletions mocks/app-function/routes/async-jsx.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default async function AsyncJsx() {
await new Promise((resolve) => setTimeout(resolve, 10)) // simulate async work
return <div>Async JSX Response</div>
}
9 changes: 9 additions & 0 deletions mocks/app-function/routes/async-response.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default async function AsyncResponse() {
return new Response(JSON.stringify({ message: 'Async Response' }), {
status: 201,
headers: {
'Content-Type': 'application/json',
'x-custom': 'async',
},
})
}
3 changes: 3 additions & 0 deletions mocks/app-function/routes/jsx-response.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function JsxResponse() {
return <div>JSX Response</div>
}
10 changes: 8 additions & 2 deletions src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,14 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
// export default function Helle() {}
if (typeof routeDefault === 'function') {
subApp.get(path, setInnerMeta)
subApp.get(path, (c) => {
return c.render(routeDefault(c), route as any)
subApp.get(path, async (c) => {
const result = await routeDefault(c)

if (result instanceof Response) {
return result
}

return c.render(result, route as any)
})
}
}
Expand Down
36 changes: 36 additions & 0 deletions test-integration/apps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -877,3 +877,39 @@ describe('Nested Dynamic Routes', () => {
expect(await res.text()).toBe('<b>Resource2 Id abcdef / 12345</b>')
})
})

describe('Function Component Response', () => {
const ROUTES = import.meta.glob('../mocks/app-function/routes/**/[a-z[-][a-z[_-]*.(tsx|ts)', {
eager: true,
})

const app = createApp({
root: '../mocks/app-function/routes',
ROUTES: ROUTES as any,
})

it('Should handle direct Response return from function component', async () => {
const res = await app.request('/api-response')
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ message: 'API Response' })
})

it('Should handle JSX return from function component', async () => {
const res = await app.request('/jsx-response')
expect(res.status).toBe(200)
expect(await res.text()).toBe('<div>JSX Response</div>')
})

it('Should handle async function component with Response', async () => {
const res = await app.request('/async-response')
expect(res.status).toBe(201)
expect(res.headers.get('x-custom')).toBe('async')
expect(await res.json()).toEqual({ message: 'Async Response' })
})

it('Should handle async function component with JSX', async () => {
const res = await app.request('/async-jsx')
expect(res.status).toBe(200)
expect(await res.text()).toBe('<div>Async JSX Response</div>')
})
})

0 comments on commit a9a1af4

Please sign in to comment.