Skip to content

Serve on a go/transport server

transport-openapi mounts onto a plain *http.ServeMux, which is exactly what a go/transport HTTP server is built around. Register your API docs on the same mux you give the transport server, and they are served alongside your API — same process, same port, same origin.

import (
    "net/http"

    transporthttp "gitlab.com/phpboyscout/go/transport/http"
    openapi "gitlab.com/phpboyscout/go/transport-openapi"
)

//go:embed openapi.yaml
var spec []byte

func newServer() (*transporthttp.Server, error) {
    mux := http.NewServeMux()

    // API handlers…
    mux.HandleFunc("GET /v1/things", listThings)

    // API docs on the same mux.
    if err := openapi.Register(mux, spec,
        openapi.WithSpecPath("/v1/openapi.yaml"),
        openapi.WithDocsPath("/v1/docs/"),
    ); err != nil {
        return nil, err
    }

    // Hand the mux to the transport server (health, lifecycle, middleware…).
    return transporthttp.NewServer(mux /* , transport options… */)
}

Now the transport server's lifecycle, health endpoints and middleware apply to the whole surface, and /v1/docs/ is a first-class route on it.

Why the same server

Serving the docs from the transport server (rather than a separate static host) keeps the spec and the try-it console same-origin with the API they document — so the console can call your endpoints without any CORS configuration. See Same-origin docs by design.

Security headers and the transport chain

Register applies go/transport's security-header middleware to the docs/spec handlers by default. If your transport server already wraps the whole mux in an equivalent header chain, opt the handler out with WithoutSecurityHeaders to avoid setting them twice.