apigenie-generatorOpenAPI serversserver go

server go

Generate a Go server for the net/http router of Go 1.22 from an OpenAPI document.

From an AsyncAPI document, the command generates a Go Kafka application instead; see apigenie-generator server go (AsyncAPI).

Usage

apigenie-generator server go [...OPTIONS] INPUT_FILE

Description

The generator writes a Go package whose code uses the standard library only. Its names and layering follow oapi-codegen (the std-http-server and strict-server targets), so code written against one of them is easy to move to the other.

File Contents
types.gen.go the types of the component schemas the operations use, and of their inline schemas
server.gen.go ServerInterface, the parameters structs, ServerInterfaceWrapper, Operations, SecuritySchemes and HandlerWithOptions
strict.gen.go StrictServerInterface, the request and response objects, and NewStrictHandler
spec.gen.go, openapi.yaml the OpenAPI document, embedded with //go:embed (RawSpec())
runtime_*.gen.go parameter binding, validation, problem details, Nullable[T], Date, multipart helpers
go.mod, cmd/<package>/main.go with layout: module (and main: true)

There are two ways to implement the server:

  • ServerInterface: one method per operation receives the http.ResponseWriter, the request, the path parameters and a struct with the query, header and cookie parameters, bound and validated. The method decodes the body and writes the response.
  • StrictServerInterface: one method per operation receives a request object (parameters and decoded, validated body) and returns a response object, e.g. GetPet200JSONResponse, with its status, typed headers and body. NewStrictHandler turns it into a ServerInterface.
mux := http.NewServeMux()
api.HandlerWithOptions(api.NewStrictHandler(server, nil), api.StdHTTPServerOptions{
    BaseURL:         "/api/v1",
    BaseRouter:      mux,
    SecurityHandler: authenticator, // runs before parameters are bound
})
log.Fatal(http.ListenAndServe(":8080", mux))

HandlerWithOptions registers one pattern per operation, e.g. GET /pets/{petId}, so routing, 405 Method Not Allowed (with Allow) and HEAD requests are handled by http.ServeMux:

  • paths ending with / are registered as /{$}, so that they don’t match the paths below them;
  • path parameters whose names aren’t Go identifiers ({pet-id}) are renamed, and parameters sharing a path segment with other text (/files/{name}.{ext}) are split out of it;
  • patterns http.ServeMux can’t register together (it panics), such as GET /a/{x}/b and GET /a/b/{y}, are served through one pattern generalizing them, which sends each request to the most specific operation. route_conflicts: error reports them as errors instead.

Types

  • Optional properties are pointers with omitempty; slices, maps and any stay values. optional_fields: omitzero uses values with omitzero (Go 1.24).
  • Optional properties that can be null are Nullable[T], which tells absent, null and set values apart; required ones are pointers. nullable_type: pointer uses pointers for both.
  • Required properties that are readOnly or writeOnly are pointers, as they are absent from requests or responses.
  • Structs that would contain themselves hold pointers.
  • Enums are defined types with constants named after the type and the value (PetStatusAvailable), PetStatusValues(), IsValid() and Validate().
  • oneOf and anyOf schemas are structs with one pointer per variant. With a discriminator, the value goes to the variant its property selects: through the mapping, the name of the schema or the value the schema gives the property (const); other values go to the defaultMapping variant (x-defaultMapping in 3.0 and 3.1 documents), or are kept in Raw. Without a discriminator, the value goes to the first variant it decodes into without unknown properties and validates against.
  • allOf schemas are merged into one struct; an anyOf or oneOf whose members only list required properties (anyOf: [{required: [email]}, {required: [phone]}]) is checked by Validate().
  • additionalProperties are kept in an AdditionalProperties map.
  • date-time strings are time.Time, date strings Date, byte and binary strings []byte (files in multipart bodies).

Validation

Every type has a Validate() method checking the constraints of its schema (lengths, patterns, bounds, multipleOf, items, properties, enums and the email, uuid, uri, hostname, ipv4, ipv6, date, date-time and time formats). Parameters and request bodies are validated before the handlers are called, and failures are answered with RFC 9457 problem details listing the failed checks:

{"title":"Bad Request","status":400,"detail":"The request is not valid.",
 "errors":[{"path":"limit","check":"maximum","message":"must be less than or equal to 100"}]}

DefaultErrorHandler maps errors to statuses: 400 for parameters and bodies, 413 for bodies larger than max_body_bytes, 415 for unsupported media types, the status of a SecurityError (401 by default) or of an error implementing StatusCode() int, and 500 otherwise.

Extensions

Extension Effect
x-go-name name of the type of a schema, or of the field of a property
x-go-type Go type of a schema, e.g. decimal.Decimal; with x-go-type-import: {path: ...} for its package
x-go-type-skip-optional-pointer the optional property isn’t a pointer
x-go-json-ignore the field gets the tag json:"-"
x-omitempty true or false overrides the omitempty of the field
x-enum-varnames, x-enumNames names of the enum constants
x-enum-descriptions comments of the enum constants
x-apigenie.codegen.name name of the type of a component schema, when it has no x-go-name
x-apigenie.codegen.action-name name of the handler method of an operation without an operationId (with the default action_naming, which lists id first)
x-apigenie.codegen.disabled true on an operation or its path item leaves the operation out
x-defaultMapping defaultMapping of a discriminator in OpenAPI 3.0 and 3.1 documents: the schema of the values whose discriminator value isn’t mapped

The extensions can live in an overlay for this target instead of in the document, e.g. go.overlay.yaml:

overlay: 1.0.0
info:
  title: Go types
  version: 1.0.0
actions:
  - target: $.components.schemas.Pet
    update:
      x-go-name: Animal
  - target: $.components.schemas.Pet.properties.price
    update:
      x-go-type: decimal.Decimal
      x-go-type-import:
        path: github.com/shopspring/decimal
apigenie-generator server go openapi.yaml --overlay go.overlay.yaml -o out

Limitations

  • Callbacks and webhooks aren’t generated, and operation and path servers are ignored: every operation is registered below the same BaseURL.
  • x-internal isn’t honoured: only x-apigenie codegen.disabled skips operations.
  • text/event-stream responses are written at once as text, so events can’t be streamed; itemSchema isn’t read, so stream items aren’t typed (application/jsonl bodies are io.Reader streams).
  • Validate() doesn’t check prefixItems, patternProperties, if/then/else, dependentRequired, dependentSchemas and unevaluatedProperties.
  • XML bodies are passed as streams (io.Reader), and form or multipart responses too.
  • Patterns using lookaround or backreferences, which Go’s regexp package doesn’t support, aren’t checked (a warning says so). Patterns are compiled when first used.
  • allOf schemas are flattened: there are no type hierarchies.
  • Exported names of the runtime (Problem, Date, File, Nullable, Operation, …) are reserved: schemas with these names get numbered types, e.g. Problem2.
  • The input must be an OpenAPI 3.0, 3.1 or 3.2 document; convert Swagger 2.0 documents with apigenie convert, and bundle documents referencing other files with apigenie bundle.

Options

-c, –config

Path to the configuration file to use. See the “Configuration” section for more information.

–overlay OVERLAY

Path to an OpenAPI Overlay (1.0 to 1.2) applied to the input before generating, e.g. one setting the extensions of the “Extensions” section. Can be repeated: the overlays apply in order, after those listed under commands.generate.server_go.overlay in the configuration file (with paths relative to it). Warnings and errors about a value an overlay set point to the overlay.

–strict

Makes an overlay action whose target selects nothing an error (exit status 2, nothing is generated) instead of a warning (OVERLAY:LINE:COL: action #N (TARGET) selects no nodes.).

-o, –output

Directory where the package is generated.

–package-name

Name of the Go package. Defaults to the name of the output directory (api when it isn’t a valid package name).

–package-version

Ignored: Go packages have no version.

-p, –property NAME=VALUE

Sets a generator option (see below), e.g. -p layout=module. Options given on the command line take precedence over the configuration file. Lists are comma-separated (-p include_tags=pets,store) and mappings too (-p type_mappings=uuid=github.com/google/uuid.UUID).

Configuration

version: '1.0'
commands:
  generate:
    server_go:
      package: petstore
      layout: module
      module: github.com/acme/petstore
      type_mappings:
        uuid: github.com/google/uuid.UUID
Option Type Default Description
package string name of the output directory Name of the Go package; also set by --package-name.
layout package or module package module also writes go.mod, making the output a module of its own.
module string example.com/<package> Module path written to go.mod.
main boolean false With layout: module, writes cmd/<package>/main.go running a server whose operations answer 501, unless the file exists.
generate list of types, server, strict all Files to write. strict requires server, which requires types.
embedded_spec boolean true Writes openapi.yaml and spec.gen.go embedding it.
optional_fields pointer or omitzero pointer Optional properties as pointers with omitempty, or as values with omitzero (Go 1.24).
nullable_type tristate or pointer tristate Optional nullable properties as Nullable[T], or as pointers.
include_tags list of strings Generates only the operations with one of these tags.
exclude_tags list of strings Skips the operations with one of these tags.
skip_prune boolean false Keeps the component schemas that no generated operation uses.
validate_requests boolean true Validates parameters and request bodies against their schemas.
validate_responses boolean false Validates the bodies of strict responses before writing them (500 when they aren’t valid).
route_conflicts warn or error warn Serve the patterns http.ServeMux can’t register together through a shared pattern, or report them as errors.
initialisms list of strings Words written in upper case in identifiers, besides ID, URL, HTTP, JSON and the other initialisms of golint.
type_mappings map of strings Go types of string formats or x-go-type names, e.g. uuid: github.com/google/uuid.UUID.
max_body_bytes integer 0 (no limit) Largest request body the strict server reads (413 beyond).
max_multipart_memory integer 33554432 Memory multipart bodies may take before their files are stored on disk.
action_naming list of id, extension, url id, extension, url Where operation names come from, in order of preference.