Skip to main content

spec-ui v0.2.0 — A Better Provider Model and Offline-Ready Binaries

· 3 min read
Oaswrap Maintainer

spec-ui v0.2.0 is a significant release. It rethinks how UI providers are selected, makes offline deployments a first-class concern, and fixes a couple of bugs that could cause subtle, hard-to-debug issues in production.

A cleaner way to select providers

The biggest change in this release is how you pick a UI provider. Previously, provider options lived in the root specui package — you'd call something like specui.WithSwaggerUI(). That worked, but it meant all provider code was always compiled into your binary regardless of which one you actually used.

In v0.2.0, each provider has its own package. You import just the one you want, and call WithUI() on it:

import (
specui "github.com/oaswrap/spec-ui"
"github.com/oaswrap/spec-ui/swaggerui"
)

handler := specui.NewHandler(
specui.WithSpecFile("openapi.yaml"),
swaggerui.WithUI(),
)

The Go linker does the rest — only the provider you imported is included in the final binary. All five providers follow the same pattern:

ProviderImport path
Swagger UIgithub.com/oaswrap/spec-ui/swaggerui
Stoplight Elementsgithub.com/oaswrap/spec-ui/stoplight
ReDocgithub.com/oaswrap/spec-ui/redoc
Scalargithub.com/oaswrap/spec-ui/scalar
RapiDocgithub.com/oaswrap/spec-ui/rapidoc

One thing to be aware of when migrating: there is no longer a default provider. Calling handler.Docs() without a WithUI() option will now panic. Previously Stoplight Elements was used as the default, so if you relied on that behavior you'll need to add an explicit import.

There's also a small naming fix for ReDoc users: config.ReDoc.DisableSearch has been renamed to config.ReDoc.HideSearch to stay consistent with the naming conventions of other providers.

Offline-ready binaries with embedded assets

By default, spec-ui loads UI assets (CSS, JavaScript) from a CDN at runtime. That's convenient for most cases, but it's a non-starter for air-gapped environments or deployments that can't reach the internet.

v0.2.0 introduces *emb packages — one for each provider — that bundle all assets directly into the binary. Switching is as simple as changing the import:

import (
specui "github.com/oaswrap/spec-ui"
"github.com/oaswrap/spec-ui/swaggeruiemb" // <-- emb variant
)

handler := specui.NewHandler(
specui.WithSpecFile("openapi.yaml"),
swaggeruiemb.WithUI(),
)

// Register the assets handler alongside your other routes
http.Handle("/docs/_assets/", handler.Assets())
http.Handle("/docs/openapi.yaml", handler.Spec())
http.Handle("/docs", handler.Docs())

Every provider has a corresponding embedded variant:

ProviderCDN packageEmbedded package
Swagger UIswaggeruiswaggeruiemb
Stoplight Elementsstoplightstoplightemb
ReDocredocredocemb
Scalarscalarscalaremb
RapiDocrapidocrapidocemb

Three new handler methods come along with this:

  • handler.Assets() — returns the HTTP handler that serves the bundled assets; nil in CDN mode
  • handler.AssetsEnabled() — tells you at runtime whether embedded mode is active
  • handler.AssetsPath() — returns the URL prefix used for assets (default /docs/_assets)

If the default assets path conflicts with your routing, you can override it with specui.WithAssetsPath("/your/path").

Bug fixes

Two bugs were fixed that could cause silent data corruption in edge cases:

  • A missing return statement in the SpecIOFS error path meant error conditions would fall through and produce a corrupted response instead of returning early. This is now handled correctly.
  • Errors from file.Close() were being silently discarded. They're now captured and surfaced properly.

Upgrade

go get github.com/oaswrap/spec-ui@v0.2.0

Check the full documentation for provider guides and the complete configuration reference.