📖 3 min read (~ 600 words).

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.

swagger: '2.0'
info:
  version: 1.0.0
  title: Greeting Server
paths:
  /hello:
    get:
      produces:
        - text/plain
      parameters:
        - name: name
          required: false
          type: string
          in: query
          description: defaults to World if not given
      operationId: getGreeting
      responses:
        200:
          description: returns a greeting
          schema:
            type: string
            description: contains the actual greeting as plain text

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:

rm -rf gen && mkdir gen
swagger generate server --exclude-main -A greeter -t gen -f ./swagger/swagger.yml

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

$ go run ./cmd/greeter/main.go --port 3000

Then exercise it (here with httpie):

$ http get :3000/hello                  # Hello, World!
$ http get :3000/hello name==Swagger    # Hello, Swagger!

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.