Skip to content

Configuration

wiki edited this page Sep 4, 2026 · 1 revision

Configuration

app := rex.New(openapi.WithOpenAPI(openapi.NewConfig(
	openapi.WithTitle("Orders API"),
	openapi.WithVersion("2.1.0"),
	openapi.WithDescription("Order placement, fulfilment and returns."),
	openapi.WithTags(
		openapi.Tag{Name: "orders", Description: "Order lifecycle"},
	),
)))

openapi.WithOpenAPI(nil) takes the defaults: title "API", version "1.0.0", served at /openapi.json, default router only.

⚠ A non-nil config is used verbatim

There is no field-by-field merge. A partial struct literal leaves everything else at its zero value:

// Wrong: Title "", Version "", ServePath "" — no path to serve at.
openapi.WithOpenAPI(&openapi.Config{Description: "…"})

// Right.
openapi.WithOpenAPI(openapi.NewConfig(openapi.WithDescription("…")))

The merge used to exist and behaved as a trap: fields it forgot were silently ignored, fields it copied unconditionally were zeroed by a partial literal, and a deliberate zero could not be expressed at all.

Fields

type Config struct {
	Title          string   // "API"
	Version        string   // "1.0.0"
	Description    string
	ServePath      string   // "/openapi.json"
	Tags           []Tag
	IncludeRouters []string // empty → the default router only
	ExcludeRouters []string // applied after IncludeRouters
	ServeOnRouter  string   // empty → the default router
}

Options

WithTitle(s) / WithVersion(s) / WithDescription(s) the info section
WithTags(tags…) top-level tag descriptions; merged, last wins on a duplicate name
WithServePath(p) where the document is served
WithServeOnRouter(name) which router serves it
WithIncludeRouters(names…) whose routes appear; "*" for all
WithExcludeRouters(names…) omit these, after include

Version the version

Version is the API version, not the build. Bump it when the contract changes, not on every deploy — a client generator keys off it, and a version that changes hourly is noise.

openapi.WithVersion("2.1.0")

A production shape

openapi.NewConfig(
	openapi.WithTitle("Orders API"),
	openapi.WithVersion(apiVersion), // a constant, bumped deliberately
	openapi.WithDescription(strings.TrimSpace(`
		Order placement, fulfilment and returns.

		Errors are RFC 9457 problem documents.
	`)),
	openapi.WithTags(
		openapi.Tag{Name: "orders", Description: "Order lifecycle"},
		openapi.Tag{Name: "returns", Description: "Return authorisations"},
	),
	// Explicit rather than implicit, so the intent survives a new router.
	openapi.WithIncludeRouters("default"),
	openapi.WithServeOnRouter("default"),
)

Generating the document outside the extension

g := openapi.NewGenerator(cfg, schemes)
doc, err := g.Generate(routes)

Useful for writing the document to a file in CI so a contract change shows up in a diff:

func TestOpenAPISnapshot(t *testing.T) {
	doc, err := openapi.NewGenerator(cfg, nil).Generate(routes())
	if err != nil {
		t.Fatal(err)
	}
	got, _ := json.MarshalIndent(doc, "", "  ")
	// compare with testdata/openapi.json
}

That is worth having: it turns "we accidentally changed the API" into a failing test rather than a support ticket.

Clone this wiki locally