mirror of
https://github.com/moby/moby.git
synced 2026-08-09 01:21:37 +00:00
254 lines
6.2 KiB
Go
254 lines
6.2 KiB
Go
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package docui
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// constants that are common to all UI-serving middlewares.
|
|
defaultDocsPath = "docs"
|
|
defaultDocsURL = "/swagger.json"
|
|
defaultDocsTitle = "API Documentation"
|
|
|
|
contentTypeHeader = "Content-Type"
|
|
applicationJSON = "application/json"
|
|
)
|
|
|
|
// UIMiddleware is a function returning a http middleware which accepts UI [Option].
|
|
type UIMiddleware func(...Option) func(http.Handler) http.Handler
|
|
|
|
// Option to tune your swagger documentation UI middleware.
|
|
//
|
|
// Options may be combined to alter the route at which the UI asset is served,
|
|
// the URL of the spec document, the source URL of the UI asset and the title of the UI page.
|
|
//
|
|
// The embedded js scriptlet served may be modified using [WithUITemplate].
|
|
type Option func(*options)
|
|
|
|
// SpecOption can be applied to the [ServeSpec] middleware.
|
|
type SpecOption func(*specOptions)
|
|
|
|
// SwaggerUIOptions define a group of extra options specific to the SwaggerUI component.
|
|
type SwaggerUIOptions struct {
|
|
// OAuth2CallbackURL sets the URL called after OAuth2 login
|
|
OAuth2CallbackURL string
|
|
|
|
// Defines the URL of the swagger UI assets with presets.
|
|
//
|
|
// Default: https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js
|
|
SwaggerPresetURL string
|
|
|
|
// Defines style sheet URL.
|
|
//
|
|
// Default: https://unpkg.com/swagger-ui-dist/swagger-ui.css
|
|
SwaggerStylesURL string
|
|
|
|
// Define the favicons URLs.
|
|
//
|
|
// Defaults:
|
|
//
|
|
// - 16x16: https://unpkg.com/swagger-ui-dist/favicon-16x16.png
|
|
// - 32x32: https://unpkg.com/swagger-ui-dist/favicon-32x32.png
|
|
Favicon32 string
|
|
Favicon16 string
|
|
}
|
|
|
|
func (o *SwaggerUIOptions) applySwaggerUIDefaults() {
|
|
if o.SwaggerPresetURL == "" {
|
|
o.SwaggerPresetURL = swaggerPresetLatest
|
|
}
|
|
if o.SwaggerStylesURL == "" {
|
|
o.SwaggerStylesURL = swaggerStylesLatest
|
|
}
|
|
if o.Favicon16 == "" || o.Favicon32 == "" {
|
|
o.Favicon16 = swaggerFavicon16Latest
|
|
o.Favicon32 = swaggerFavicon32Latest
|
|
}
|
|
}
|
|
|
|
type (
|
|
options struct {
|
|
SwaggerUIOptions
|
|
|
|
// BasePath for the UI, defaults to: /
|
|
BasePath string
|
|
|
|
// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
|
|
Path string
|
|
|
|
// SpecURL is the URL of the spec document.
|
|
SpecURL string
|
|
|
|
// Title for the documentation site, default to: API documentation
|
|
Title string
|
|
|
|
// Template specifies a custom template to serve the UI
|
|
Template string
|
|
|
|
// AssetsURL points to the js asset that generates the documentation page.
|
|
AssetsURL string
|
|
}
|
|
|
|
specOptions struct {
|
|
Path string
|
|
Document string
|
|
}
|
|
)
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Common UI options
|
|
////////////////////////////////////////////////////////////
|
|
|
|
// WithUIBasePath sets the base path from where to serve the UI assets.
|
|
//
|
|
// Default: "/"
|
|
func WithUIBasePath(base string) Option {
|
|
return func(o *options) {
|
|
if !strings.HasPrefix(base, "/") {
|
|
base = "/" + base
|
|
}
|
|
o.BasePath = base
|
|
}
|
|
}
|
|
|
|
// WithUIPath sets the path from where to serve the UI assets (i.e. /{basepath}/{path}).
|
|
//
|
|
// Default: "docs"
|
|
func WithUIPath(pth string) Option {
|
|
return func(o *options) {
|
|
o.Path = pth
|
|
}
|
|
}
|
|
|
|
// WithUITitle sets the title of the UI.
|
|
//
|
|
// Default: "API documentation"
|
|
func WithUITitle(title string) Option {
|
|
return func(o *options) {
|
|
o.Title = title
|
|
}
|
|
}
|
|
|
|
// WithUIAssetsURL sets the URL from where to fetch the js assets.
|
|
//
|
|
// Defaults:
|
|
//
|
|
// - for Redoc: https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js
|
|
// - for RapiDoc, this defaults to: https://unpkg.com/rapidoc/dist/rapidoc-min.js
|
|
// - for SwaggerUI: https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js
|
|
func WithUIAssetsURL(assets string) Option {
|
|
return func(o *options) {
|
|
o.AssetsURL = assets
|
|
}
|
|
}
|
|
|
|
// WithUITemplate allows to set a custom template for the UI.
|
|
//
|
|
// This allows the caller to fully customize the rendered UI, using the advanced options
|
|
// provided by any UI.
|
|
//
|
|
// The UI [middleware] will panic if the template does not parse or execute properly.
|
|
//
|
|
// Reference documentations to customize your js scriptlet:
|
|
//
|
|
// - for Redoc: https://github.com/Redocly/redoc/blob/main/docs/deployment/html.md
|
|
// - for RapiDoc: https://github.com/rapi-doc/RapiDoc
|
|
// - for SwaggerUI: https://github.com/swagger-api/swagger-ui
|
|
func WithUITemplate[StringOrBytes ~string | ~[]byte](tpl StringOrBytes) Option {
|
|
return func(o *options) {
|
|
o.Template = string(tpl)
|
|
}
|
|
}
|
|
|
|
// WithSpecURL sets the URL of the spec document.
|
|
//
|
|
// Defaults to: /swagger.json
|
|
func WithSpecURL(u string) Option {
|
|
return func(o *options) {
|
|
o.SpecURL = u
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// SwaggerUI UI options
|
|
////////////////////////////////////////////////////////////
|
|
|
|
func WithSwaggerUIOptions(opts SwaggerUIOptions) Option {
|
|
return func(o *options) {
|
|
o.SwaggerUIOptions = opts
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Spec options
|
|
////////////////////////////////////////////////////////////
|
|
|
|
// WithSpecPath sets the path of the spec document.
|
|
//
|
|
// This is "/swagger.json" by default.
|
|
func WithSpecPath(pth string) SpecOption {
|
|
return func(o *specOptions) {
|
|
if pth == "" {
|
|
return
|
|
}
|
|
|
|
o.Path = pth
|
|
}
|
|
}
|
|
|
|
// WithSpecPathFromOptions reuses the same SpecPath as the one specified in
|
|
// a set of UI [Option] (extract the path from the URL provided by [WithSpecURL]).
|
|
func WithSpecPathFromOptions(opts ...Option) SpecOption {
|
|
return func(o *specOptions) {
|
|
uiOpts := optionsWithDefaults(opts)
|
|
|
|
// If the spec URL is provided, there is a non-default path to serve the spec.
|
|
//
|
|
// This makes sure that the UI middleware is aligned with the Spec middleware.
|
|
u, _ := url.Parse(uiOpts.SpecURL)
|
|
|
|
if u.Path == "" {
|
|
return
|
|
}
|
|
|
|
o.Path = u.Path
|
|
}
|
|
}
|
|
|
|
func optionsWithDefaults(opts []Option, prepend ...Option) options {
|
|
o := options{
|
|
BasePath: "/",
|
|
Path: defaultDocsPath,
|
|
SpecURL: defaultDocsURL,
|
|
Title: defaultDocsTitle,
|
|
}
|
|
|
|
prepend = append(prepend, opts...)
|
|
for _, apply := range prepend {
|
|
apply(&o)
|
|
}
|
|
|
|
return o
|
|
}
|
|
|
|
func specOptionsWithDefaults(opts []SpecOption) specOptions {
|
|
o := specOptions{
|
|
Path: defaultDocsURL,
|
|
}
|
|
|
|
for _, apply := range opts {
|
|
apply(&o)
|
|
}
|
|
|
|
if !strings.HasPrefix(o.Path, "/") {
|
|
o.Path = "/" + o.Path
|
|
}
|
|
|
|
return o
|
|
}
|