Pular para o conteúdo
Esta página ainda não foi traduzida. O conteúdo abaixo está em inglês. Ler em inglês

APIs

OpenAPI and API reference

Generate an OpenAPI 3.1 document from your routes, check responses against it, export TypeScript/Zod types and serve a Scalar API reference.

Última atualização:

The document#

Go
func API(r *router.Router, app *vukem.App) error {
	vukem.ServeOpenAPI(app, r, "/openapi.json")
	apidocs.Serve(app, r, "/docs", apidocs.Config{Theme: "purple"})
	// api.Register(...) routes
	return nil
}
Terminal
vukem openapi:export > openapi.json

openapi:export and codegen:types build the app in warmup mode: no provider Boot, no database connection, APP_KEY optional. A warmup app never boots or serves (Boot and Run return vukem.ErrWarmupRun), so never expose its router from a custom main.

VariableDefaultMeaning
APP_NAMEVukeminfo.title
API_VERSION1.0.0info.version
OPENAPI_PREFIXemptykeep only routes under it, e.g. /api
OPENAPI_IN_PRODUCTIONfalseserve /openapi.json and /docs in production

vukem.ServeOpenAPIWith(app, r, "/api/v1/openapi.json", vukem.OpenAPIOptions{PathPrefix: "/api/v1", InProduction: true}) sets the prefix in code and opts one document into production; OPENAPI_PREFIX stays the default for ServeOpenAPI.

  • Typed handlers are described from their types: json tags give property names, validate rules give constraints (required, min/max/len, email, url, uuid, oneof, regex, positive, unique, dive…), and a doc:"..." tag becomes the description.
  • required lists the key in required. On a string it also emits minLength: 1, since an empty string is rejected; on a list it emits no minItems, since an empty list passes (tag min=1 when items are needed).
  • Named structs become components/schemas; orm relations and orm.NullTime map to their JSON shape; errors reference shared Problem and ValidationError responses; Op.Security names become security requirements (bearer is predefined).
  • Plain routes get a generic entry; hide one with .Doc(openapi.Skip{}).
  • app.OpenAPI() returns the document, and openapi.Generate(r.Routes(), openapi.Info{...}) builds one directly. CI validates a golden document with Redocly.

Checking responses in tests#

Go
app.Client(t).GetJSON("/api/v1/products").AssertOK().AssertMatchesOpenAPI()

AssertMatchesOpenAPI finds the operation for the request path and checks the body against the schema of the response status (or the default problem response). Outside tests, doc.ValidateResponse(method, path, status, body) does the same.

Types for clients#

Terminal
vukem codegen:types -o resources/js/api.ts        # TypeScript types
vukem codegen:types -zod -o resources/js/api.ts   # plus Zod 4 schemas (zod 4.0+)

You get one type per component schema plus <Operation>Body, <Operation>Query and <Operation>Response for every named operation, and, with -zod, Zod 4 validators: <Name>Schema per component and <Operation>BodySchema per JSON request body (inline bodies included). The command builds the app in warmup mode: no provider Boot, so no database connection, and APP_KEY may be unset (routes that need the key at build time still fail closed), so CI can run it without secrets. A component whose name would shadow a TypeScript or DOM global, or a name the generated client declares (Number, String, Object, Date, Error, Promise, Record, Array, Response, Request, URL, Client, ...), gets a Type suffix: a Go type Number becomes NumberType (Zod: NumberTypeSchema). If two generated names still collide (a Number and a NumberType schema, a component named like an operation type such as <Op>Body or <Op>Params, or two operation names that map to the same identifier), codegen:types and codegen:client fail with an error naming the duplicate instead of emitting code that does not compile. CI type-checks the golden output with tsc --strict.

Any z schema also exports on its own: z.JSONSchema(schema) returns JSON Schema 2020-12 (types, required keys, lengths, ranges, formats, patterns, enums, defaults, descriptions; Refine/Custom logic cannot be expressed).

API reference with Scalar#

Go
apidocs.Serve(app, r, "/docs", apidocs.Config{
	SpecURL:        "/openapi.json",
	Theme:          "purple",
	Layout:         "modern",
	Authentication: map[string]any{"preferredSecurityScheme": "bearer"},
})
  • The Scalar bundle (@scalar/api-reference 1.72.3, MIT) is vendored, embedded and pinned by SHA-256: no CDN, no telemetry, no remote fonts, no AI agent.
  • The page runs under the app's nonce-only CSP (no 'unsafe-inline'): it passes the request nonce to Scalar (a csp-nonce meta and a small page.js shim that nonces the <style> elements Scalar creates and applies the plain size/overflow style attributes it sets through the CSSOM; any other style attribute is left to CSP, which blocks it). HTML from the OpenAPI document (descriptions) never gets the nonce: its <style> elements and style attributes stay blocked. Scalar's "Generate MCP" link and developer-tools header (both scalar.com services) are off. Its policy is apidocs.CSP, the default one plus data: fonts; connect-src 'self' keeps "try it" requests on your origin. Inline styles inside HTML that Scalar injects (code highlighting) stay blocked, except the numeric line-number variables, which the shim re-applies.
  • Accessibility: the default theme gets AA text colors (muted text, HTTP method labels) and the shim makes the scrollable endpoint list keyboard-focusable and puts the visible text into the "Show More" buttons' accessible names, so the page passes axe serious checks in light and dark mode (checked by hand with axe-core 4.10; TestDefaultThemeColorsMeetAA keeps the colors at 4.5:1). Other themes keep their own colors.
  • Like /openapi.json, it is not registered in production unless OPENAPI_IN_PRODUCTION=true or Config.InProduction (one page only). For a public, versioned API serve its document and page explicitly:
Go
vukem.ServeOpenAPIWith(app, r, "/api/v1/openapi.json",
	vukem.OpenAPIOptions{PathPrefix: "/api/v1", InProduction: true})
apidocs.Serve(app, r, "/api/docs", apidocs.Config{SpecURL: "/api/v1/openapi.json", InProduction: true})
  • The apidocs package (about 4 MB) is linked only when you import it. Add apidocs.Command() to your commands for vukem openapi:serve [-addr localhost:8081], a local preview.