chanfana icon indicating copy to clipboard operation
chanfana copied to clipboard

fromHono options "base" is not respected

Open john-ko opened this issue 2 months ago • 5 comments

steps to reproduce

npm create cloudflare@latest -- my-first-worker

-> Application starter -> API starter ... cd my-first-worker edit src/index.ts and add to fromHono options

base: "/api/v1"
Image

npm run dev

  • curl 'http://localhost:8787/api/v1/api/tasks?page=1' -> 404
  • curl 'http://localhost:8787/api/tasks?page=1 -> 200

john-ko avatar Nov 01 '25 18:11 john-ko

I think base means that app would be mounted at example.com/api/v1, so app ignore /api/v1 when parsing route and add /api/v1 (such as return redirect url)

It also confuse me a lot.

const app = new Hono()
const openapi = fromHono(app, { base: '/api/v1' })

openapi.get('/home', (ctx) => ctx.text('home'))

openapi.get('/', (ctx) => ctx.redirect('/home')) 
// Location: /home, because ctx is from Hono and Hono does not know base

console.log(openapi.routes.map((r) => r.path))
// [
//   '/docs',
//   '/redocs',
//   '/api/v1/openapi.json',
//   '/api/v1/openapi.yaml',
//   '/home',
//   '/'
// ]
//
// only openapi_url is added base, docs not work

export default app

expected:

const app = new Hono({ base: '/api/v1' }) // actually not support
const openapi = fromHono(app)

openapi.get('/home', (ctx) => ctx.text('home'))
openapi.get('/', (ctx) => ctx.redirect('/home')) // Location: /api/v1/home

console.log(openapi.routes.map((r) => r.path))
// [
//   '/docs',
//   '/redocs',
//   '/openapi.json',
//   '/openapi.yaml',
//   '/home',
//   '/'
// ]

export default app

boobam22 avatar Nov 02 '25 09:11 boobam22

const api = new Hono().basePath('/api');
const openapi = fromHono(api, {
  base: ''
});
openapi.post('/register', Register);
openapi.post('/login', Login);
openapi.post('/logout', Logout);

// Start a Hono app
const app = new Hono();
app.use(cors());
app.route('/', api);

console.log(app.routes.map((r) => r.path));

Routes registered:

[
  '/*',
  '/api/docs',
  '/api/redocs',
  '/api/openapi.json',
  '/api/openapi.yaml',
  '/api/register',
  '/api/login',
  '/api/logout'
]

When navigated to /api/docs Swagger is trying to load /openapi.json which will fail.

When I change the base:

const openapi = fromHono(api, {
  base: '/api'
});
[
  '/*',
  '/api/docs',
  '/api/redocs',
  '/api/api/openapi.json',
  '/api/api/openapi.yaml',
  '/api/register',
  '/api/login',
  '/api/logout'
]

When navigated to /api/docs Swagger is trying to load /api/openapi.json which will fail again.

milesich avatar Nov 02 '25 14:11 milesich

import { Hono } from 'hono'
import { basePath } from 'hono/route'
import { fromHono, getSwaggerUI } from 'chanfana'

const app = new Hono().basePath('/api')
const openapi = fromHono(app)

openapi.get('/home', (ctx) => ctx.text('home'))
openapi.get('/base', (ctx) => ctx.text(basePath(ctx)))
openapi.get('/', (ctx) => ctx.redirect(`${basePath(ctx)}/home`))
openapi.get('/fixed-docs', (ctx) => ctx.html(getSwaggerUI(`${basePath(ctx)}/openapi.json`)))

console.log(openapi.routes.map((r) => r.path))

export default app

config basePath only in Hono, and Openapi need not concern what basePath is.

boobam22 avatar Nov 02 '25 17:11 boobam22

the docs https://chanfana.pages.dev/openapi-configuration-customization#base-setting-the-base-path-for-api-routes

says this:

The base option allows you to set a base path for all API routes managed by Chanfana. If provided, this base path will be prepended to all route paths when generating the OpenAPI document. This is useful when your API is served under a specific path prefix (e.g., /api/v1).

john-ko avatar Nov 02 '25 19:11 john-ko

i think the issue is within this function https://github.com/cloudflare/chanfana/blob/main/src/adapters/hono.ts#L106

but haven't had much time to look deep into it

john-ko avatar Nov 02 '25 19:11 john-ko