diff --git a/api.go b/api.go index a8039bf4..eeffec40 100644 --- a/api.go +++ b/api.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "html" "io" "mime/multipart" "net/http" @@ -205,6 +206,20 @@ type Config struct { // route altogether. DocsRenderer string + // DocsRendererConfig is an optional renderer-specific config. When set, it is + // JSON-marshaled into the docs HTML. Scalar and SwaggerUI use it, Stoplight + // Elements ignores it. + // + // Scalar reads it from the `data-configuration` attribute. See + // https://github.com/scalar/scalar/blob/main/documentation/configuration.md + // for the options. + // + // SwaggerUI merges its fields into the SwaggerUIBundle config object. See + // https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/ + // for the options. Huma owns the `url` and `dom_id` fields, so setting + // them here does nothing. + DocsRendererConfig any + // SchemasPath is the path to the API schemas. If set to `/schemas` it will // allow clients to get `/schemas/{schema}` to view the schema in a browser // or for use in editors like VSCode to provide autocomplete & validation. @@ -640,6 +655,15 @@ func (a *api) registerDocsRoute() { "style-src 'unsafe-inline'", // TODO: Somehow drop 'unsafe-inline' } + var configAttr string + if a.config.DocsRendererConfig != nil { + b, err := json.Marshal(a.config.DocsRendererConfig) + if err != nil { + panic("failed to marshal DocsRendererConfig: " + err.Error()) + } + configAttr = ` data-configuration="` + html.EscapeString(string(b)) + `"` + } + body = []byte(` @@ -649,7 +673,7 @@ func (a *api) registerDocsRoute() { ` + title + ` - + `) @@ -700,10 +724,19 @@ func (a *api) registerDocsRoute() { "form-action 'none'", "frame-ancestors 'none'", "sandbox allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox", - "script-src https://unpkg.com/swagger-ui-dist@5.31.1/swagger-ui-bundle.js 'sha256-loGQL86SKUDRkBgfqt+XGmcml9Plihleifquht4CLYE='", + "script-src https://unpkg.com/swagger-ui-dist@5.31.1/swagger-ui-bundle.js 'sha256-gRya58TMnKTH/Tne/zBInjBwFUxL66aMDYvPuAX0lNY='", "style-src https://unpkg.com/swagger-ui-dist@5.31.1/swagger-ui.css", } + var configAttr string + if a.config.DocsRendererConfig != nil { + b, err := json.Marshal(a.config.DocsRendererConfig) + if err != nil { + panic("failed to marshal DocsRendererConfig: " + err.Error()) + } + configAttr = ` data-config="` + html.EscapeString(string(b)) + `"` + } + body = []byte(` @@ -716,10 +749,13 @@ func (a *api) registerDocsRoute() {
- - - -`)) -}) +api := humachi.New(router, config) ``` ![Scalar Docs](./scalar.png) ### Stoplight Elements -You can customize the default docs by providing your own HTML so you can set the layout, styles, colors, etc as needed. +[Stoplight Elements](https://stoplight.io/open-source/elements) is the default renderer, so you get it without setting `config.DocsRenderer` at all. It doesn't read `config.DocsRendererConfig`. ```go title="code.go" router := chi.NewRouter() config := huma.DefaultConfig("Docs Example", "1.0.0") -config.DocsPath = "" api := humachi.New(router, config) - -router.Get("/docs", func(w http.ResponseWriter, r *http.Request) { - // Please refer to the "DocsRendererStoplightElements" renderer code inside api.go on what to return here -}) ``` ![Stoplight Elements Stacked](./elements-stacked.png) @@ -96,13 +69,16 @@ router.Get("/docs", func(w http.ResponseWriter, r *http.Request) { ```go title="code.go" router := chi.NewRouter() config := huma.DefaultConfig("Docs Example", "1.0.0") -config.DocsPath = "" +config.DocsRenderer = huma.DocsRendererSwaggerUI -api := humachi.New(router, config) +// Optional. These fields are merged into the SwaggerUIBundle config object. See +// https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/ +config.DocsRendererConfig = map[string]any{ + "defaultModelsExpandDepth": -1, // hide the models section + "tryItOutEnabled": true, // enable "Try it out" by default +} -router.Get("/docs", func(w http.ResponseWriter, r *http.Request) { - // Please refer to the "DocsRendererSwaggerUI" renderer code inside api.go on what to return here -}) +api := humachi.New(router, config) ``` ![SwaggerUI](./swaggerui.png)