Skip to content

Commit a9a1af4

Browse files
authored
feat: add support for Response in component routing (#266)
1 parent ba7279d commit a9a1af4

File tree

6 files changed

+65
-2
lines changed

6 files changed

+65
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default function ApiResponse() {
2+
return new Response(JSON.stringify({ message: 'API Response' }), {
3+
headers: { 'Content-Type': 'application/json' },
4+
})
5+
}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default async function AsyncJsx() {
2+
await new Promise((resolve) => setTimeout(resolve, 10)) // simulate async work
3+
return <div>Async JSX Response</div>
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default async function AsyncResponse() {
2+
return new Response(JSON.stringify({ message: 'Async Response' }), {
3+
status: 201,
4+
headers: {
5+
'Content-Type': 'application/json',
6+
'x-custom': 'async',
7+
},
8+
})
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function JsxResponse() {
2+
return <div>JSX Response</div>
3+
}

src/server/server.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,14 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
182182
// export default function Helle() {}
183183
if (typeof routeDefault === 'function') {
184184
subApp.get(path, setInnerMeta)
185-
subApp.get(path, (c) => {
186-
return c.render(routeDefault(c), route as any)
185+
subApp.get(path, async (c) => {
186+
const result = await routeDefault(c)
187+
188+
if (result instanceof Response) {
189+
return result
190+
}
191+
192+
return c.render(result, route as any)
187193
})
188194
}
189195
}

test-integration/apps.test.ts

+36
Original file line numberDiff line numberDiff line change
@@ -877,3 +877,39 @@ describe('Nested Dynamic Routes', () => {
877877
expect(await res.text()).toBe('<b>Resource2 Id abcdef / 12345</b>')
878878
})
879879
})
880+
881+
describe('Function Component Response', () => {
882+
const ROUTES = import.meta.glob('../mocks/app-function/routes/**/[a-z[-][a-z[_-]*.(tsx|ts)', {
883+
eager: true,
884+
})
885+
886+
const app = createApp({
887+
root: '../mocks/app-function/routes',
888+
ROUTES: ROUTES as any,
889+
})
890+
891+
it('Should handle direct Response return from function component', async () => {
892+
const res = await app.request('/api-response')
893+
expect(res.status).toBe(200)
894+
expect(await res.json()).toEqual({ message: 'API Response' })
895+
})
896+
897+
it('Should handle JSX return from function component', async () => {
898+
const res = await app.request('/jsx-response')
899+
expect(res.status).toBe(200)
900+
expect(await res.text()).toBe('<div>JSX Response</div>')
901+
})
902+
903+
it('Should handle async function component with Response', async () => {
904+
const res = await app.request('/async-response')
905+
expect(res.status).toBe(201)
906+
expect(res.headers.get('x-custom')).toBe('async')
907+
expect(await res.json()).toEqual({ message: 'Async Response' })
908+
})
909+
910+
it('Should handle async function component with JSX', async () => {
911+
const res = await app.request('/async-jsx')
912+
expect(res.status).toBe(200)
913+
expect(await res.text()).toBe('<div>Async JSX Response</div>')
914+
})
915+
})

0 commit comments

Comments
 (0)