hono
hono copied to clipboard
Swagger Editor middleware
What is the feature you are proposing?
Like this:
https://editor.swagger.io/
We may make it without depending external libraries, but I think it should be a 3rd party middleware.
For Stoplight Elements, the code we use looks like:
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi'
import { logger } from 'hono/logger'
declare type Bindings = {
ENVIRONMENT: "dev" | "production";
};
declare type Env = {
Bindings: Bindings;
};
const ParamsSchema = z.object({
id: z
.string()
.min(3)
.openapi({
param: {
name: 'id',
in: 'path',
},
example: '1212121',
}),
})
const UserSchema = z
.object({
id: z.string().openapi({
example: '123',
}),
name: z.string().openapi({
example: 'John Doe',
}),
age: z.number().openapi({
example: 42,
}),
})
const route = createRoute({
method: 'get',
path: '/users/{id}',
request: {
params: ParamsSchema,
},
responses: {
200: {
content: {
'application/json': {
schema: UserSchema,
},
},
description: 'Retrieve the user',
},
},
})
const app = new OpenAPIHono<Env>()
app.use('*', logger())
app.openapi(route, (c) => {
const { id } = c.req.valid('param')
console.debug(c.env.ENVIRONMENT)
return c.jsonT({
id,
age: 20,
name: 'Ultra-man',
})
})
app.doc('/openapi.json', {
openapi: '3.0.0',
info: {
version: '1.0.0',
title: 'My API'
},
tags: [
{
name: 'language',
description: 'en'
}
]
})
app.get('/docs/', (c) => {
return c.html(`<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>API Docs</title>
<meta name="author" content="ai.moda">
<meta name="title" content="API Docs" />
<script async src="https://stoplight-elements.ai.moda/web-components.min.js"></script>
<link rel="stylesheet" href="https://stoplight-elements.ai.moda/styles.min.css">
</head>
<body>
<div style="height: 100vh;">
<elements-api
apiDescriptionUrl="/openapi.json"
router="hash"
layout="sidebar"
tryItCredentialsPolicy="include"
withCredentials="true"
/>
</div>
</body>
</html>
`, 200, {
'Content-Security-Policy': "default-src 'none'; script-src https://stoplight-elements.ai.moda/web-components.min.js 'unsafe-eval'; style-src https://stoplight-elements.ai.moda/styles.min.css 'unsafe-inline'; connect-src 'self'"
})
})
export default app
Thanks @Manouchehri
Or, I think we can also make "swagger-ui" - @hono/swagger-ui
middleware using swagger-ui-dist
via CDN:
https://swagger.io/docs/open-source-tools/swagger-ui/usage/installation/
Is there anyone make it?
cc: @sor4chi
I think it is almost the same as the way with the stoplight element.
Here is an example using swagger-ui-dist
!
import type { Context } from 'hono'
export function swaggerUI() {
return async (c: Context) =>
c.html(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/swagger-ui-bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/swagger-ui.min.css" rel="stylesheet">
</head>
<body>
<div id="swagger-ui"></div>
<script>
window.onload = function() {
SwaggerUIBundle({
url: '/openapi.json',
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
})
}
</script>
</body>
</html>
`)
}
~~I'm trying to see if I can't take advantage of being a thirdparty and pass the return value of createRoute directly to the swaggerUI Middleware option.~~
I also updated https://github.com/honojs/hono/issues/1415#issuecomment-1707531030 to include the correct and "best" CORS rule (that I know of right now) for Stoplight Elements. 😄
@yusukebe @Manouchehri should this be an optional config on @hono/zod-openapi
?
@rafaell-lycan
No. I think it should be a middleware independent of @hono/zod-openapi
like https://github.com/honojs/middleware/pull/168
Swagger UI Middleware is published, but Swagger UI is not Swagger Editor: https://github.com/swagger-api/swagger-editor
Opps, I see.