Skip to content

Why a companion module

transport-openapi could have been a package inside go/transport — it mounts on a transport server's mux and depends on transport's security-header middleware. It is a separate module for one concrete reason: the size of what it embeds.

The 2.4 MB embed

The interactive docs UI is Stoplight Elements, vendored as two files:

Asset Size
web-components.min.js ~2.08 MB
styles.min.css ~297 KB

Both are //go:embed-ed into the binary. That is the price of shipping a self-contained docs site — a project needs only its generated spec, never a per-project copy of the UI front-end. It is a price worth paying when you serve docs.

If this lived in go/transport core, that ~2.4 MB would be linked into every transport-server binary — including the many services that expose no public API docs at all. A background worker with a health endpoint would carry a 2.4 MB Stoplight blob for no reason.

Opt-in by module boundary

Making it a separate import moves the cost to exactly the tools that want it:

  • Import go/transport → you get the server stack, no docs UI, no embed.
  • Also import go/transport-openapi → you opt into the docs handler and its embed.

Go's linker only includes packages that are imported, so the boundary is the switch. This mirrors the transport-metrics companion and the general transport-<companion> pattern in the toolkit: the transport core stays lean, and heavier or more specialised concerns live in companions that a tool adds only when it needs them.

What it still shares

Being a separate module does not mean duplicating transport. transport-openapi depends on go/transport and go/transit — it reuses their security-header middleware and Middleware type rather than reimplementing them. It is a companion, not a fork: lean core, opt-in extras, shared contracts.