Swagger UI "urls" config shows "No API definition provided."
Which middleware has the bug?
@hono/swagger-ui
What version of the middleware?
0.5.2
What version of Hono are you using?
4.9.8
What runtime/platform is your app running on? (with version if possible)
Node v20.19.2
What steps can reproduce the bug?
When using @hono/swagger-ui with the urls array, the UI renders but shows "No API definition provided." and does not auto-load a spec. Single url works as expected.
Environment
- Node: v20.19.2 (also tested with Bun 1.2.21)
- npm: 11.4.2
- hono: 4.9.8
- @hono/swagger-ui: 0.5.2
- @hono/zod-openapi: 1.1.3
Steps
- Create routes with
@hono/zod-openapiserving/v1/users/openapi.jsonand/v1/widgets/openapi.json. - Mount Swagger UI with only "urls":
app.get('/docs', swaggerUI({
urls: [
{ url: '/v1/users/openapi.json', name: 'Users API' },
{ url: '/v1/widgets/openapi.json', name: 'Widgets API' },
],
}))
- Navigate to
/docs. UI shows "No API definition provided."
Repro
https://github.com/frasergr/hono-swagger-ui-issue-example
What is the expected behavior?
With urls provided, the first entry should auto-load and there should be a way to select other entries.
What do you see instead?
/docs UI shows "No API definition provided."
Additional information
No response
@frasergr Thank you for the issue.
Hey, @naporin0624 @sor4chi ! Can one of the two take a look at this?
Hey folks I poked around and I think I found what’s happening + a path forward.
What’s going on
From what I gathered (e.g. via this StackOverflow thread), the urls option in Swagger UI only works if the TopBar plugin is enabled — and that plugin is bundled into the Standalone preset.  So even if you pass urls, unless you include swagger-ui-standalone-preset (or otherwise bring in the TopBar plugin), the dropdown for multiple specs won’t show up. In short: you’re passing urls, but you haven’t included the necessary preset that makes urls function.
Proposal
To make this work cleanly in our middleware, I suggest adding a flag like enableStandalone. • If enableStandalone: true, then we inject (or generate) a
That way it’s opt-in (no surprise weight for users who don’t need it), but for those who do want multiple Swagger endpoints, they can turn it on.
If you like, I can whip up a draft PR with this change and we can iterate the naming / implementation. Do you want me to put that together?
@sor4chi
Thanks!
If you like, I can whip up a draft PR with this change and we can iterate the naming / implementation. Do you want me to put that together?
It's your middleware. Up to you.