📖 3 min read (~ 600 words).

Todo list server

The todo-list example is the canonical go-swagger server: a small CRUD API generated from a spec, wired to a trivial in-memory store. It’s the best place to see what swagger generate server produces and which files you’re expected to edit.

Prefer a step-by-step build? Start with the todo-list tutorial. This page is the reference tour of the finished example.

Tip

Source: todo-list/. Regenerate with go run ./hack/tools regen (or the //go:generate directive in restapi/configure_todo_list.go).

The spec

Two definitions drive everything: an item (with a required, minLength: 1 description and a read-only id) and a generic error.

item:
  type: object
  required:
    - description
  properties:
    id:
      type: integer
      format: int64
      readOnly: true
    description:
      type: string
      minLength: 1
    completed:
      type: boolean
error:
  type: object
  required:
    - message
  properties:
    code:
      type: integer
      format: int64
    message:
      type: string

Full source: todo-list/swagger.yml

The readOnly: true on id means the server assigns it — clients that send one have it ignored on create.

Generated models

Each definition becomes a Go struct. Note how the spec constraints map onto the type: description is required and minLength: 1, so it’s generated as a non-pointer-safe *string carrying validation, while the read-only id is a plain int64.

type Item struct {

	// completed
	Completed bool `json:"completed,omitempty"`

	// description
	// Required: true
	// Min Length: 1
	Description *string `json:"description"`

	// id
	// Read Only: true
	ID int64 `json:"id,omitempty"`
}

Full source: todo-list/models/item.go

The generator also emits the validation methods that enforce the spec’s constraints at runtime — here the description field’s required and minLength: 1 rules, wired straight from the spec. You never hand-write this:

func (m *Item) validateDescription(formats strfmt.Registry) error {

	if err := validate.Required("description", "body", m.Description); err != nil {
		return err
	}

	if err := validate.MinLength("description", "body", *m.Description, 1); err != nil {
		return err
	}

	return nil
}

Full source: todo-list/models/item.go

Wiring the handlers

restapi/configure_todo_list.go is the one file you edit — it’s marked safe to edit and survives regeneration. The generated scaffold leaves each handler returning 501 Not Implemented; you replace those with real logic. Here’s the implemented version from the tutorial’s server-complete, backing the store with a map:

api.TodosAddOneHandler = todos.AddOneHandlerFunc(func(params todos.AddOneParams) middleware.Responder {
	if err := addItem(params.Body); err != nil {
		return todos.NewAddOneDefault(500).WithPayload(&models.Error{Code: 500, Message: conv.Pointer(err.Error())})
	}
	return todos.NewAddOneCreated().WithPayload(params.Body)
})
api.TodosDestroyOneHandler = todos.DestroyOneHandlerFunc(func(params todos.DestroyOneParams) middleware.Responder {
	if err := deleteItem(params.ID); err != nil {
		return todos.NewDestroyOneDefault(500).WithPayload(&models.Error{Code: 500, Message: conv.Pointer(err.Error())})
	}
	return todos.NewDestroyOneNoContent()
})

Full source: tutorials/todo-list/server-complete/restapi/configure_todo_list.go

Each response constructor (NewAddOneCreated, NewDestroyOneNoContent, …) is generated from a response you declared in the spec, so the compiler keeps your handlers honest against the contract.

Running it

The generated server listens on a Unix socket, HTTP and HTTPS by default. For a quick local test, enable just the HTTP listener on a fixed port:

$ go run ./todo-list/cmd/todo-list-server --scheme=http --port=8765
serving todo list at http://127.0.0.1:8765
$ curl -i localhost:8765 \
    -H 'Content-Type: application/io.goswagger.examples.todo-list.v1+json' \
    -d '{"description":"go shopping"}'
HTTP/1.1 201 Created
...
{"description":"go shopping","id":1}

See the todo-list README for the full listener matrix (unix/http/https) and TLS options.

Variations