Custom server tutorial
The todo-list tutorial generated a whole server — main.go
and all — and you edited the configure_*.go file it left for you. Sometimes you
want the opposite balance: keep go-swagger’s generated core (the models,
router, and typed operations) but own the main yourself, so the CLI is a thin
hand-written layer that wires configuration and handlers around that core.
That’s what --exclude-main is for. This tutorial builds a tiny greeter server
that way.
Info
You’ll need the swagger CLI on your PATH — see
goswagger.io. The finished code lives
under tutorials/custom-server/.
Step 1 — the spec
The greeter is deliberately minimal: one GET /hello that takes an optional
name query parameter and returns a plain-text greeting.
Step 2 — generate the core only
Generate the server into a gen/ sub-tree with --exclude-main, so go-swagger
emits everything except a main.go:
You get gen/restapi/ — the embedded spec, the NewServer constructor, the
router, and operations/ with the typed GreeterAPI, its GetGreetingParams,
and the GetGreetingOK responder. What you don’t get is a cmd/ entry point.
That’s yours to write.
Step 3 — write your own main
Your main does what the generated main.go would have — load the embedded spec,
construct the API, and hand it to NewServer — but it’s plain code you control:
// load embedded swagger file
swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "")
if err != nil {
return err
}
// create new service API
api := operations.NewGreeterAPI(swaggerSpec)
server := restapi.NewServer(api)Full source: tutorials/custom-server/cmd/greeter/main.go
Because you own this file, you can add your own flags, config loading, dependency injection, logging, or lifecycle management around this core — none of it is generated, none of it gets overwritten on regeneration.
Step 4 — attach the handler
The generated GreeterAPI exposes one handler field per operation. Assign your
implementation to GetGreetingHandler before serving — this is the same handler
you’d otherwise place in a generated configure_*.go, but here it lives in your
main:
// GetGreetingHandler greets the given name,
// in case the name is not given, it will default to World
api.GetGreetingHandler = operations.GetGreetingHandlerFunc(
func(params operations.GetGreetingParams) middleware.Responder {
name := conv.Value(params.Name)
if name == "" {
name = "World"
}
greeting := fmt.Sprintf("Hello, %s!", name)
return operations.NewGetGreetingOK().WithPayload(greeting)
})Full source: tutorials/custom-server/cmd/greeter/main.go
conv.Value dereferences the optional *string parameter, defaulting to World,
and NewGetGreetingOK().WithPayload(...) returns the typed 200 responder the
generated code defined.
Step 5 — run it
Then exercise it (here with httpie):
Regenerating safely
The whole point of the split is that regeneration only ever touches gen/. When
the spec changes, rerun the Step 2 command — gen/ is rewritten, your cmd/
main is untouched. Keep the two apart (generated core under gen/, your code
outside it) and the two never collide.
Related
- Todo list tutorial — the opposite balance: generate the whole server and edit
configure_*.go. - Custom middleware guide — extend a fully generated server via its hook points, no
--exclude-mainneeded. - Generation flags guide — other flags that reshape the generated
main.