spec-ui v0.2.0 — A Better Provider Model and Offline-Ready Binaries
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:
| Provider | Import path |
|---|---|
| Swagger UI | github.com/oaswrap/spec-ui/swaggerui |
| Stoplight Elements | github.com/oaswrap/spec-ui/stoplight |
| ReDoc | github.com/oaswrap/spec-ui/redoc |
| Scalar | github.com/oaswrap/spec-ui/scalar |
| RapiDoc | github.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:
| Provider | CDN package | Embedded package |
|---|---|---|
| Swagger UI | swaggerui | swaggeruiemb |
| Stoplight Elements | stoplight | stoplightemb |
| ReDoc | redoc | redocemb |
| Scalar | scalar | scalaremb |
| RapiDoc | rapidoc | rapidocemb |
Three new handler methods come along with this:
handler.Assets()— returns the HTTP handler that serves the bundled assets;nilin CDN modehandler.AssetsEnabled()— tells you at runtime whether embedded mode is activehandler.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
returnstatement in theSpecIOFSerror 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.