Giter VIP home page Giter VIP logo

oapi-codegen's Introduction

oapi-codegen

oapi-codegen is a command-line tool and library to convert OpenAPI specifications to Go code, be it server-side implementations, API clients, or simply HTTP models.

Using oapi-codegen allows you to reduce the boilerplate required to create or integrate with services based on OpenAPI 3.0, and instead focus on writing your business logic, and working on the real value-add for your organisation.

With oapi-codegen, there are a few Key Design Decisions we've made, including:

  • idiomatic Go, where possible
  • fairly simple generated code, erring on the side of duplicate code over nicely refactored code
  • supporting as much of OpenAPI 3.x as is possible, alongside Go's type system

oapi-codegen is one part of a wider ecosystem, which can be found described in further detail in the oapi-codegen organisation on GitHub.

โš ๏ธ This README may be for the latest development version, which may contain unreleased changes. Please ensure you're looking at the README for the latest release version.

Install

It is recommended to follow the tools.go pattern for managing the dependency of oapi-codegen alongside your core application.

This would give you a tools/tools.go:

//go:build tools
// +build tools

package main

import (
	_ "github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen"
)

Then, each invocation of oapi-codegen would be used like so:

//go:generate go run github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../../api.yaml

Alternatively, you can install it as a binary with:

$ go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@latest
$ oapi-codegen -version

Which then means you can invoke it like so:

//go:generate oapi-codegen --config=config.yaml ../../api.yaml

Pinning to commits

While the project does not (yet) have a defined release cadence, there may be cases where you want to pull in yet-unreleased changes to your codebase.

Therefore, you may want to pin your dependency on oapi-codegen to a given commit hash, rather than a tag.

This is officially recommended for consumers of oapi-codegen, who want features/bug fixes that haven't yet been released.

We aim to keep the default branch ready-to-release so you should be able to safely pin.

To do so, you can run:

# pin to the latest version on the default branch
$ go get github.com/deepmap/oapi-codegen/v2@master
# alternatively, to a commit hash i.e. https://github.com/deepmap/oapi-codegen/commit/71e916c59688a6379b5774dfe5904ec222b9a537
$ go get github.com/deepmap/oapi-codegen/v2@71e916c59688a6379b5774dfe5904ec222b9a537

This will then make a change such as:

diff --git go.mod go.mod
index 44f29a4..436a780 100644
--- go.mod
+++ go.mod
@@ -2,21 +2,20 @@
-require github.com/deepmap/oapi-codegen/v2 v2.1.0
+require github.com/deepmap/oapi-codegen/v2 v2.1.1-0.20240331212514-80f0b978ef16

Usage

oapi-codegen is largely configured using a YAML configuration file, to simplify the number of flags that users need to remember, and to make reading the go:generate command less daunting.

For full details of what is supported, it's worth checking out the GoDoc for codegen.Configuration.

We also have a JSON Schema that can be used by IDEs/editors with the Language Server Protocol (LSP) to perform intelligent suggestions, i.e.:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
package: api
# ...

Backwards compatibility

Although we strive to retain backwards compatibility - as a project that's using a stable API per SemVer - there are sometimes opportunities we must take to fix a bug that could cause a breaking change for people relying upon the behaviour.

In this case, we will expose a compatibility option to restore old behaviour.

Features

At a high level, oapi-codegen supports:

  • Generating server-side boilerplate for a number of servers (docs)
  • Generating client API boilerplate (docs)
  • Generating the types (docs)
  • Splitting large OpenAPI specs across multiple packages(docs)
    • This is also known as "Import Mapping" or "external references" across our documentation / discussion in GitHub issues

What does it look like?

Below we can see a trimmed down example taken from the OpenAPI Petstore example:

// generated code

type ServerInterface interface {
	// ...
	// Returns all pets
	// (GET /pets)
	FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams)
	// ...
}

// FindPets operation middleware
func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	var err error

	// Parameter object where we will unmarshal all parameters from the context
	var params FindPetsParams

	// ------------- Optional query parameter "tags" -------------

	err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), &params.Tags)
	if err != nil {
		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
		return
	}

	// ------------- Optional query parameter "limit" -------------

	err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), &params.Limit)
	if err != nil {
		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
		return
	}

	handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		siw.Handler.FindPets(w, r, params)
	}))

	for _, middleware := range siw.HandlerMiddlewares {
		handler = middleware(handler)
	}

	handler.ServeHTTP(w, r.WithContext(ctx))
}

// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
	m := options.BaseRouter

	if m == nil {
		m = http.NewServeMux()
	}
	if options.ErrorHandlerFunc == nil {
		options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
	}

	wrapper := ServerInterfaceWrapper{
		Handler:            si,
		HandlerMiddlewares: options.Middlewares,
		ErrorHandlerFunc:   options.ErrorHandlerFunc,
	}

	m.HandleFunc("GET "+options.BaseURL+"/pets", wrapper.FindPets)

	return m
}

Then, in your own code, you implement the underlying logic for the FindPets implementation:

type PetStore struct {
	Pets   map[int64]Pet
	NextId int64
	Lock   sync.Mutex
}

// Make sure we conform to ServerInterface

var _ ServerInterface = (*PetStore)(nil)

func NewPetStore() *PetStore {
	return &PetStore{
		Pets:   make(map[int64]Pet),
		NextId: 1000,
	}
}

// FindPets implements all the handlers in the ServerInterface
func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) {
	p.Lock.Lock()
	defer p.Lock.Unlock()

	var result []Pet

	for _, pet := range p.Pets {
		if params.Tags != nil {
			// If we have tags,  filter pets by tag
			for _, t := range *params.Tags {
				if pet.Tag != nil && (*pet.Tag == t) {
					result = append(result, pet)
				}
			}
		} else {
			// Add all pets if we're not filtering
			result = append(result, pet)
		}

		if params.Limit != nil {
			l := int(*params.Limit)
			if len(result) >= l {
				// We're at the limit
				break
			}
		}
	}

	w.WriteHeader(http.StatusOK)
	_ = json.NewEncoder(w).Encode(result)
}

As we can see, oapi-codegen simplifies some of the boilerplate by taking parameters out of the request and instead allows us to focus on the implementation.

You'll note that there's still a bit more marshaling of request/response data, which is further reduced by using the Strict server functionality.

When using the strict server, you'll have the following generated code:

// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
	// ...
	// Returns all pets
	// (GET /pets)
	FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error)
	// ...
}

func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
	return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}

// FindPets operation middleware
func (sh *strictHandler) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) {
	var request FindPetsRequestObject

	request.Params = params

	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
		return sh.ssi.FindPets(ctx, request.(FindPetsRequestObject))
	}
	for _, middleware := range sh.middlewares {
		handler = middleware(handler, "FindPets")
	}

	response, err := handler(r.Context(), w, r, request)

	if err != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, err)
	} else if validResponse, ok := response.(FindPetsResponseObject); ok {
		if err := validResponse.VisitFindPetsResponse(w); err != nil {
			sh.options.ResponseErrorHandlerFunc(w, r, err)
		}
	} else if response != nil {
		sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
	}
}

Then, in your own code, you implement the underlying logic for the FindPets implementation:

// Make sure we conform to StrictServerInterface

var _ StrictServerInterface = (*PetStore)(nil)

func NewPetStore() *PetStore {
	return &PetStore{
		Pets:   make(map[int64]Pet),
		NextId: 1000,
	}
}

// FindPets implements all the handlers in the ServerInterface
func (p *PetStore) FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error) {
	p.Lock.Lock()
	defer p.Lock.Unlock()

	var result []Pet

	for _, pet := range p.Pets {
		if request.Params.Tags != nil {
			// If we have tags,  filter pets by tag
			for _, t := range *request.Params.Tags {
				if pet.Tag != nil && (*pet.Tag == t) {
					result = append(result, pet)
				}
			}
		} else {
			// Add all pets if we're not filtering
			result = append(result, pet)
		}

		if request.Params.Limit != nil {
			l := int(*request.Params.Limit)
			if len(result) >= l {
				// We're at the limit
				break
			}
		}
	}

	return FindPets200JSONResponse(result), nil
}

We can see that this provides the best means to focus on the implementation of the business logic within the endpoint, rather than (un)marshalling types to and from JSON, or wrangling cookies or headers.

Key design decisions

  • Produce an interface that can be satisfied by your implementation, with reduced boilerplate
  • Bulk processing and parsing of OpenAPI document in Go
  • Resulting output is using Go's text/templates, which are user-overridable
  • Attempts to produce Idiomatic Go
  • Single-file output
  • Support multiple OpenAPI files by having a package-per-OpenAPI file
  • Support of OpenAPI 3.0
  • Extract parameters from requests, to reduce work required by your implementation
  • Implicit additionalProperties are ignored by default (more details)
  • Prune unused types by default

Generating server-side boilerplate

oapi-codegen shines by making it fairly straightforward (note that this is a purposeful choice of wording here - we want to avoid words like "easy") to generate the server-side boilerplate for a backend API.

Below you can find the supported servers, and more information about how to implement a server using them.

To provide you a fully Test Driven Development style test harness to confirm you are following the specification, you could use a tool such as openapi.tanna.dev/go/validator, or craft your own.

Supported Servers

Right now, we support the following servers, and are supportive of adding new servers, too!

Server generate flag to enable code generation Example usage

Chi

chi-server

For a Chi server, you will want a configuration file such as:

# yaml-language-server: ...
package: api
generate:
  chi-server: true
  models: true
output: gen.go

To implement this, check out the Chi docs.

Echo

echo-server

For an Echo server, you will want a configuration file such as:

# yaml-language-server: ...
package: api
generate:
  echo-server: true
  models: true
output: gen.go

To implement this, check out the Echo docs.

Fiber

fiber-server

For a Fiber server, you will want a configuration file such as:

# yaml-language-server: ...
package: api
generate:
  fiber-server: true
  models: true
output: gen.go

To implement this, check out the Fiber docs.

Gin

gin-server

For a Gin server, you will want a configuration file such as:

# yaml-language-server: ...
package: api
generate:
  gin-server: true
  models: true
output: gen.go

To implement this, check out the Gin docs.

gorilla/mux

gorilla-server

For a gorilla/mux server, you will want a configuration file such as:

# yaml-language-server: ...
package: api
generate:
  gorilla-server: true
  models: true
output: gen.go

To implement this, check out the gorilla/mux docs.

Iris

iris-server

For a Iris server, you will want a configuration file such as:

# yaml-language-server: ...
package: api
generate:
  iris-server: true
  models: true
output: gen.go

To implement this, check out the Iris docs.

1.22+ net/http

std-http-server

To use purely net/http (for Go 1.22+), you will want a configuration file such as:

# yaml-language-server: ...
package: api
generate:
  stdhttp-server: true
  models: true
output: gen.go

To implement this, check out the Go 1.22+ net/http docs.

Go 1.22+ net/http

As of Go 1.22, enhancements have been made to the routing of the net/http package in the standard library, which makes it a great starting point for implementing a server with, before needing to reach for another router or a full framework.

For instance, let's take this straightforward specification:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Minimal ping API server
paths:
  /ping:
    get:
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pong'
components:
  schemas:
    # base types
    Pong:
      type: object
      required:
        - ping
      properties:
        ping:
          type: string
          example: pong

This then generates code such as:

// Pong defines model for Pong.
type Pong struct {
	Ping string `json:"ping"`
}

// ServerInterface represents all server handlers.
type ServerInterface interface {

	// (GET /ping)
	GetPing(w http.ResponseWriter, r *http.Request)
}

func HandlerFromMux(si ServerInterface, m *http.ServeMux) http.Handler {
	return HandlerWithOptions(si, StdHTTPServerOptions{
		BaseRouter: m,
	})
}

// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
	m := options.BaseRouter

	// ... omitted for brevity

	m.HandleFunc("GET "+options.BaseURL+"/ping", wrapper.GetPing)

	return m
}

To implement this HTTP server, we need to write the following code in our api/impl.go:

import (
	"encoding/json"
	"net/http"
)

// optional code omitted

type Server struct{}

func NewServer() Server {
	return Server{}
}

// (GET /ping)
func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
	resp := Pong{
		Ping: "pong",
	}

	w.WriteHeader(http.StatusOK)
	_ = json.NewEncoder(w).Encode(resp)
}

Now we've got our implementation, we can then write the following code to wire it up and get a running server:

import (
	"log"
	"net/http"

	"github.com/deepmap/oapi-codegen/v2/examples/minimal-server/stdhttp/api"
)

func main() {
	// create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
	server := api.NewServer()

	r := http.NewServeMux()

	// get an `http.Handler` that we can use
	h := api.HandlerFromMux(server, r)

	s := &http.Server{
		Handler: h,
		Addr:    "0.0.0.0:8080",
	}

	// And we serve HTTP until the world ends.
	log.Fatal(s.ListenAndServe())
}

Note

This doesn't include validation of incoming requests.

Note

If you feel like you've done everything right, but are still receiving 404 page not found errors, make sure that you've got the go directive in your go.mod updated to:

go 1.22

Chi

For instance, let's take this straightforward specification:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Minimal ping API server
paths:
  /ping:
    get:
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pong'
components:
  schemas:
    # base types
    Pong:
      type: object
      required:
        - ping
      properties:
        ping:
          type: string
          example: pong

This then generates code such as:

// Pong defines model for Pong.
type Pong struct {
	Ping string `json:"ping"`
}

// ServerInterface represents all server handlers.
type ServerInterface interface {

	// (GET /ping)
	GetPing(w http.ResponseWriter, r *http.Request)
}

// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
	return HandlerWithOptions(si, ChiServerOptions{
		BaseRouter: r,
	})
}

// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
	r := options.BaseRouter

	// ...

	r.Group(func(r chi.Router) {
		r.Get(options.BaseURL+"/ping", wrapper.GetPing)
	})

	return r
}

To implement this HTTP server, we need to write the following code in our api/impl.go:

import (
	"encoding/json"
	"net/http"
)

// optional code omitted

type Server struct{}

func NewServer() Server {
	return Server{}
}

// (GET /ping)
func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
	resp := Pong{
		Ping: "pong",
	}

	w.WriteHeader(http.StatusOK)
	_ = json.NewEncoder(w).Encode(resp)
}

Now we've got our implementation, we can then write the following code to wire it up and get a running server:

import (
	"log"
	"net/http"

	"github.com/deepmap/oapi-codegen/v2/examples/minimal-server/chi/api"
	"github.com/go-chi/chi/v5"
)

func main() {
	// create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
	server := api.NewServer()

	r := chi.NewMux()

	// get an `http.Handler` that we can use
	h := api.HandlerFromMux(server, r)

	s := &http.Server{
		Handler: h,
		Addr:    "0.0.0.0:8080",
	}

	// And we serve HTTP until the world ends.
	log.Fatal(s.ListenAndServe())
}

Note

This doesn't include validation of incoming requests.

gorilla/mux

For instance, let's take this straightforward specification:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Minimal ping API server
paths:
  /ping:
    get:
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pong'
components:
  schemas:
    # base types
    Pong:
      type: object
      required:
        - ping
      properties:
        ping:
          type: string
          example: pong

This then generates code such as:

// Pong defines model for Pong.
type Pong struct {
	Ping string `json:"ping"`
}

// ServerInterface represents all server handlers.
type ServerInterface interface {

	// (GET /ping)
	GetPing(w http.ResponseWriter, r *http.Request)
}

// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
	return HandlerWithOptions(si, GorillaServerOptions{
		BaseRouter: r,
	})
}

// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
	r := options.BaseRouter

	// ...

	r.HandleFunc(options.BaseURL+"/ping", wrapper.GetPing).Methods("GET")

	return r
}

To implement this HTTP server, we need to write the following code in our api/impl.go:

import (
	"encoding/json"
	"net/http"
)

// optional code omitted

type Server struct{}

func NewServer() Server {
	return Server{}
}

// (GET /ping)
func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
	resp := Pong{
		Ping: "pong",
	}

	w.WriteHeader(http.StatusOK)
	_ = json.NewEncoder(w).Encode(resp)
}

Now we've got our implementation, we can then write the following code to wire it up and get a running server:

import (
	"log"
	"net/http"

	"github.com/deepmap/oapi-codegen/v2/examples/minimal-server/gorillamux/api"
	"github.com/gorilla/mux"
)

func main() {
	// create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
	server := api.NewServer()

	r := mux.NewRouter()

	// get an `http.Handler` that we can use
	h := api.HandlerFromMux(server, r)

	s := &http.Server{
		Handler: h,
		Addr:    "0.0.0.0:8080",
	}

	// And we serve HTTP until the world ends.
	log.Fatal(s.ListenAndServe())
}

Note

This doesn't include validation of incoming requests.

Echo server

For instance, let's take this straightforward specification:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Minimal ping API server
paths:
  /ping:
    get:
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pong'
components:
  schemas:
    # base types
    Pong:
      type: object
      required:
        - ping
      properties:
        ping:
          type: string
          example: pong

This then generates code such as:

// Pong defines model for Pong.
type Pong struct {
	Ping string `json:"ping"`
}

// ServerInterface represents all server handlers.
type ServerInterface interface {

	// (GET /ping)
	GetPing(ctx echo.Context) error
}

// This is a simple interface which specifies echo.Route addition functions which
// are present on both echo.Echo and echo.Group, since we want to allow using
// either of them for path registration
type EchoRouter interface {
	// ...
	GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
	// ...
}

// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
	RegisterHandlersWithBaseURL(router, si, "")
}

// Registers handlers, and prepends BaseURL to the paths, so that the paths
// can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
	// ...

	router.GET(baseURL+"/ping", wrapper.GetPing)

}

To implement this HTTP server, we need to write the following code in our api/impl.go:

import (
	"net/http"

	"github.com/labstack/echo/v4"
)

// optional code omitted

type Server struct{}

func NewServer() Server {
	return Server{}
}

// (GET /ping)
func (Server) GetPing(ctx echo.Context) error {
	resp := Pong{
		Ping: "pong",
	}

	return ctx.JSON(http.StatusOK, resp)
}

Now we've got our implementation, we can then write the following code to wire it up and get a running server:

import (
	"log"

	"github.com/deepmap/oapi-codegen/v2/examples/minimal-server/echo/api"
	"github.com/labstack/echo/v4"
)

func main() {
	// create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
	server := api.NewServer()

	e := echo.New()

	api.RegisterHandlers(e, server)

	// And we serve HTTP until the world ends.
	log.Fatal(e.Start("0.0.0.0:8080"))
}

Note

This doesn't include validation of incoming requests.

Fiber server

For instance, let's take this straightforward specification:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Minimal ping API server
paths:
  /ping:
    get:
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pong'
components:
  schemas:
    # base types
    Pong:
      type: object
      required:
        - ping
      properties:
        ping:
          type: string
          example: pong

This then generates code such as:

// Pong defines model for Pong.
type Pong struct {
	Ping string `json:"ping"`
}

// ServerInterface represents all server handlers.
type ServerInterface interface {

	// (GET /ping)
	GetPing(c *fiber.Ctx) error
}

// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
func RegisterHandlers(router fiber.Router, si ServerInterface) {
	RegisterHandlersWithOptions(router, si, FiberServerOptions{})
}

// RegisterHandlersWithOptions creates http.Handler with additional options
func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
	// ...

	router.Get(options.BaseURL+"/ping", wrapper.GetPing)
}

To implement this HTTP server, we need to write the following code in our api/impl.go:

import (
	"net/http"

	"github.com/gofiber/fiber/v2"
)

// ensure that we've conformed to the `ServerInterface` with a compile-time check
var _ ServerInterface = (*Server)(nil)

type Server struct{}

func NewServer() Server {
	return Server{}
}

// (GET /ping)
func (Server) GetPing(ctx *fiber.Ctx) error {
	resp := Pong{
		Ping: "pong",
	}

	return ctx.
		Status(http.StatusOK).
		JSON(resp)
}

Now we've got our implementation, we can then write the following code to wire it up and get a running server:

import (
	"log"

	"github.com/deepmap/oapi-codegen/v2/examples/minimal-server/fiber/api"
	"github.com/gofiber/fiber/v2"
)

func main() {
	// create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
	server := api.NewServer()

	app := fiber.New()

	api.RegisterHandlers(app, server)

	// And we serve HTTP until the world ends.
	log.Fatal(app.Listen("0.0.0.0:8080"))
}

Note

This doesn't include validation of incoming requests.

Gin server

For instance, let's take this straightforward specification:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Minimal ping API server
paths:
  /ping:
    get:
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pong'
components:
  schemas:
    # base types
    Pong:
      type: object
      required:
        - ping
      properties:
        ping:
          type: string
          example: pong

This then generates code such as:

// Pong defines model for Pong.
type Pong struct {
	Ping string `json:"ping"`
}

// ServerInterface represents all server handlers.
type ServerInterface interface {

	// (GET /ping)
	GetPing(c *gin.Context)
}

// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
func RegisterHandlers(router gin.IRouter, si ServerInterface) {
	RegisterHandlersWithOptions(router, si, GinServerOptions{})
}

// RegisterHandlersWithOptions creates http.Handler with additional options
func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
	// ...

	router.GET(options.BaseURL+"/ping", wrapper.GetPing)
}

To implement this HTTP server, we need to write the following code in our api/impl.go:

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// optional code omitted

type Server struct{}

func NewServer() Server {
	return Server{}
}

// (GET /ping)
func (Server) GetPing(ctx *gin.Context) {
	resp := Pong{
		Ping: "pong",
	}

	ctx.JSON(http.StatusOK, resp)
}

Now we've got our implementation, we can then write the following code to wire it up and get a running server:

import (
	"log"
	"net/http"

	"github.com/deepmap/oapi-codegen/v2/examples/minimal-server/gin/api"
	"github.com/gin-gonic/gin"
)

func main() {
	// create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
	server := api.NewServer()

	r := gin.Default()

	api.RegisterHandlers(r, server)

	// And we serve HTTP until the world ends.

	s := &http.Server{
		Handler: r,
		Addr:    "0.0.0.0:8080",
	}

	// And we serve HTTP until the world ends.
	log.Fatal(s.ListenAndServe())
}

Note

This doesn't include validation of incoming requests.

Iris server

For instance, let's take this straightforward specification:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Minimal ping API server
paths:
  /ping:
    get:
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pong'
components:
  schemas:
    # base types
    Pong:
      type: object
      required:
        - ping
      properties:
        ping:
          type: string
          example: pong

This then generates code such as:

// Pong defines model for Pong.
type Pong struct {
	Ping string `json:"ping"`
}

// ServerInterface represents all server handlers.
type ServerInterface interface {

	// (GET /ping)
	GetPing(ctx iris.Context)
}

// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
func RegisterHandlers(router *iris.Application, si ServerInterface) {
	RegisterHandlersWithOptions(router, si, IrisServerOptions{})
}

// RegisterHandlersWithOptions creates http.Handler with additional options
func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, options IrisServerOptions) {
	// ...

	router.Get(options.BaseURL+"/ping", wrapper.GetPing)

	router.Build()
}

To implement this HTTP server, we need to write the following code in our api/impl.go:

import (
	"net/http"

	"github.com/kataras/iris/v12"
)

// optional code omitted

type Server struct{}

func NewServer() Server {
	return Server{}
}

// (GET /ping)
func (Server) GetPing(ctx iris.Context) {
	resp := Pong{
		Ping: "pong",
	}

	ctx.StatusCode(http.StatusOK)
	_ = ctx.JSON(resp)
}

Now we've got our implementation, we can then write the following code to wire it up and get a running server:

import (
	"log"

	"github.com/deepmap/oapi-codegen/v2/examples/minimal-server/iris/api"
	"github.com/kataras/iris/v12"
)

func main() {
	// create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
	server := api.NewServer()

	i := iris.Default()

	api.RegisterHandlers(i, server)

	// And we serve HTTP until the world ends.
	log.Fatal(i.Listen("0.0.0.0:8080"))
}

Note

This doesn't include validation of incoming requests.

Strict server

oapi-codegen also supports generating a server that is much more strict with the contract that the implementer requires, and takes inspiration from server-side code generation for RPC servers.

This takes the boilerplate reduction from the non-strict servers and adds additional boilerplate reduction, allowing you to make the following changes to your function signatures:

-FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams)
+FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error)

This is the highest level of strictness that oapi-codegen supports right now, and it's a good idea to start with this if you want the most guardrails to simplify developing your APIs.

The strict server has support for:

  • multiple request/response media types and status codes on a given operation
  • first-class support for multipart/form-data and application/x-www-form-urlencoded requests
  • returning an HTTP 500 Internal Server Error, when an error is returned from a function
  • automagic (un)marshalling of request/responses, and setting content-type and HTTP status codes on responses
  • binding request values to a struct, a multipart.Reader or providing a io.Reader

You can see a little more detail of the generated code in the "What does it look like" section.

Note

To configure the strict server generation, you must specify another server to be generated. For instance:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
package: api
generate:
  # NOTE another server must be added!
  chi-server: true
  strict-server: true
output: server.gen.go

Note

This doesn't include validation of incoming requests.

Generating API clients

As well as generating the server-side boilerplate, oapi-codegen can also generate API clients.

This aims to be an API client that can be used to interact with the methods of the API, and is perfectly suited for production usage.

However, if you were looking for a slightly more SDK-style approach, or a mix of generated tests and/or documentation, this API client may not be for you, and you may want to look at alternate tooling.

For instance, given an api.yaml:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Generate models
paths:
  /client:
    get:
      operationId: getClient
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClientType"
    put:
      operationId: updateClient
      responses:
        400:
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                required:
                - code
components:
  schemas:
    ClientType:
      type: object
      required:
        - name
      properties:
        name:
          type: string
    # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
    #
    # output-options:
    #   skip-prune: true
    Unreferenced:
      type: object
      required:
        - id
      properties:
        id:
          type: integer

And a cfg.yaml:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
package: client
output: client.gen.go
generate:
  models: true
  client: true

And a generate.go:

package client

//go:generate go run github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml

This would then generate:

package client

// ...

// ClientType defines model for ClientType.
type ClientType struct {
	Name string `json:"name"`
}

// ...

// Client which conforms to the OpenAPI3 specification for this service.
type Client struct {
	// The endpoint of the server conforming to this interface, with scheme,
	// https://api.deepmap.com for example. This can contain a path relative
	// to the server, such as https://api.deepmap.com/dev-test, and all the
	// paths in the swagger spec will be appended to the server.
	Server string

	// Doer for performing requests, typically a *http.Client with any
	// customized settings, such as certificate chains.
	Client HttpRequestDoer

	// A list of callbacks for modifying requests which are generated before sending over
	// the network.
	RequestEditors []RequestEditorFn
}

// ...

// The interface specification for the client above.
type ClientInterface interface {
	// GetClient request
	GetClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)

	// UpdateClient request
	UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
}

// ...

// ClientWithResponsesInterface is the interface specification for the client with responses above.
type ClientWithResponsesInterface interface {
	// GetClientWithResponse request
	GetClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClientResponse, error)

	// UpdateClientWithResponse request
	UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error)
}

type GetClientResponse struct {
	Body         []byte
	HTTPResponse *http.Response
	JSON200      *ClientType
}

// ...

With this generated client, it is then possible to construct and utilise the client, for instance:

package client_test

import (
	"context"
	"fmt"
	"log"
	"net/http"

	"github.com/deepmap/oapi-codegen/v2/examples/client"
)

func TestClient_canCall() {
	// custom HTTP client
	hc := http.Client{}

	// with a raw http.Response
	{
		c, err := client.NewClient("http://localhost:1234", client.WithHTTPClient(&hc))
		if err != nil {
			log.Fatal(err)
		}

		resp, err := c.GetClient(context.TODO())
		if err != nil {
			log.Fatal(err)
		}
		if resp.StatusCode != http.StatusOK {
			log.Fatalf("Expected HTTP 200 but received %d", resp.StatusCode)
		}
	}

	// or to get a struct with the parsed response body
	{
		c, err := client.NewClientWithResponses("http://localhost:1234", client.WithHTTPClient(&hc))
		if err != nil {
			log.Fatal(err)
		}

		resp, err := c.GetClientWithResponse(context.TODO())
		if err != nil {
			log.Fatal(err)
		}
		if resp.StatusCode() != http.StatusOK {
			log.Fatalf("Expected HTTP 200 but received %d", resp.StatusCode())
		}

		fmt.Printf("resp.JSON200: %v\n", resp.JSON200)
	}

}

Generating API models

If you're looking to only generate the models for interacting with a remote service, for instance if you need to hand-roll the API client for whatever reason, you can do this as-is.

Tip

Try to define as much as possible within the #/components/schemas object, as oapi-codegen will generate all the types here.

Although we can generate some types based on inline definitions in i.e. a path's response type, it isn't always possible to do this, or if it is generated, can be a little awkward to work with as it may be defined as an anonymous struct.

For instance, given an api.yaml:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Generate models
paths:
  /client:
    get:
      operationId: getClient
      responses:
        200:
          content:
            application/json:
              schema:
                # NOTE that Client is generated here, because it's within #/components/schemas
                $ref: "#/components/schemas/Client"
    put:
      operationId: updateClient
      responses:
        400:
          content:
            application/json:
              # NOTE that this anonymous object is /not/ generated because it's an anonymous, but would be generated if using `generate: client`
              # See https://github.com/deepmap/oapi-codegen/issues/1512
              schema:
                type: object
                properties:
                  code:
                    type: string
                required:
                - code
components:
  schemas:
    Client:
      type: object
      required:
        - name
      properties:
        name:
          type: string
    # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
    #
    # output-options:
    #   skip-prune: true
    Unreferenced:
      type: object
      required:
        - id
      properties:
        id:
          type: integer

And a cfg.yaml:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
package: onlymodels
output: only-models.gen.go
generate:
  models: true

And a generate.go:

package onlymodels

//go:generate go run github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml

This would then generate:

package onlymodels

// Client defines model for Client.
type Client struct {
	Name string `json:"name"`
}

If you wish to also generate the Unreferenced type, you would need the following cfg.yaml:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
package: onlymodels
output: only-models.gen.go
generate:
  models: true
output-options:
  # NOTE that this is only required for the `Unreferenced` type
  skip-prune: true

For a complete example see examples/only-models.

Splitting large OpenAPI specs across multiple packages (aka "Import Mapping" or "external references")

When you've got a large OpenAPI specification, you may find it useful to split the contents of the spec across multiple files, using external references, such as:

components:
  schemas:
    User:
      $ref: '../common/api.yaml#/components/schemas/User'

This is supported by oapi-codegen, through the ability to perform "Import Mapping".

For instance, let's say that we have a large API, which has a user-facing API and an admin API, both of which use a common set of API models.

In this case, we may have an Admin API that looks like:

# admin/api.yaml
openapi: "3.0.0"
info:
  version: 1.0.0
  title: Admin API
  description: The admin-only portion of the API, which has its own separate OpenAPI spec
tags:
  - name: admin
    description: Admin API endpoints
  - name: user
    description: API endpoint that pertains to user data
paths:
  /admin/user/{id}:
    get:
      tags:
        - admin
        - user
      summary: Get a user's details
      operationId: getUserById
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      $ref: '../common/api.yaml#/components/schemas/User'

This references the common spec:

# common/api.yaml
components:
  schemas:
    User:
      type: object
      additionalProperties: false
      properties:
        name:
          type: string
      required:
        - name

And finally we have our configuration file:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
# admin/cfg.yaml
package: admin
output: server.gen.go
generate:
  models: true
  chi-server: true
output-options:
  # to make sure that all types are generated
  skip-prune: true
# NOTE that this won't work, as it's missing `import-mapping`

If we were to run oapi-codegen, this will fail with the following error

error generating code: error creating operation definitions: error generating response definitions: error generating request body definition: error turning reference (../common/api.yaml#/components/schemas/User) into a Go type: unrecognized external reference '../common/api.yaml'; please provide the known import for this reference using option --import-mapping

This is because oapi-codegen requires:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
package: admin
output: server.gen.go
generate:
  models: true
  chi-server: true
output-options:
  # to make sure that all types are generated
  skip-prune: true
import-mapping:
  # for a given file/URL that is $ref'd, point `oapi-codegen` to the Go package that this spec is generated into, to perform Go package imports
  ../common/api.yaml: github.com/deepmap/oapi-codegen/v2/examples/import-mapping/common

This will then generate the following code:

package admin

import (
	// ...
	externalRef0 "github.com/deepmap/oapi-codegen/v2/examples/import-mapping/common"
)

// User defines model for User.
type User = externalRef0.User

If you don't want to do this, an alternate option is to bundle your multiple OpenAPI files into a single spec.

Check out the import-mapping example for the full code.

Generating Nullable types

It's possible that you want to be able to determine whether a field isn't sent, is sent as null or has a value.

For instance, if you had the following OpenAPI property:

S:
  type: object
  properties:
    Field:
      type: string
      nullable: true
    required: []

The default behaviour in oapi-codegen is to generate:

type S struct {
	Field *string `json:"field,omitempty"`
}

However, you lose the ability to understand the three cases, as there's no way to distinguish two of the types from each other:

  • is this field not sent? (Can be checked with S.Field == nil)
  • is this field null? (Can be checked with S.Field == nil)
  • does this field have a value? (S.Field != nil && *S.Field == "123")

As of oapi-codegen v2.1.0 it is now possible to represent this with the nullable.Nullable type from our new library, oapi-codegen/nullable.

If you configure your generator's Output Options to opt-in to this behaviour, as so:

output-options:
  nullable-type: true

You will now receive the following output:

type S struct {
    // note that there's no pointer here, just `omitempty`
    Field nullable.Nullable[string] `json:"field,omitempty"`
}

OpenAPI extensions

As well as the core OpenAPI support, we also support the following OpenAPI extensions, as denoted by the OpenAPI Specification Extensions.

Extension Description Example usage

x-go-type
x-go-type-import

Override the generated type definition (and optionally, add an import from another package)

Using the x-go-type (and optionally, x-go-type-import when you need to import another package) allows overriding the type that oapi-codegen determined the generated type should be.

We can see this at play with the following schemas:

components:
  schemas:
    Client:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        id:
          type: number
    ClientWithExtension:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          # this is a bit of a contrived example, as you could instead use
          # `format: uuid` but it explains how you'd do this when there may be
          # a clash, for instance if you already had a `uuid` package that was
          # being imported, or ...
          x-go-type: googleuuid.UUID
          x-go-type-import:
            path: github.com/google/uuid
            name: googleuuid
        id:
          type: number
          # ... this is also a bit of a contrived example, as you could use
          # `type: integer` but in the case that you know better than what
          # oapi-codegen is generating, like so:
          x-go-type: int64

From here, we now get two different models:

// Client defines model for Client.
type Client struct {
	Id   *float32 `json:"id,omitempty"`
	Name string   `json:"name"`
}

// ClientWithExtension defines model for ClientWithExtension.
type ClientWithExtension struct {
	Id   *int64          `json:"id,omitempty"`
	Name googleuuid.UUID `json:"name"`
}

You can see this in more detail in the example code.

x-go-type-skip-optional-pointer

Do not add a pointer type for optional fields in structs

By default, oapi-codegen will generate a pointer for optional fields.

Using the x-go-type-skip-optional-pointer extension allows omitting that pointer.

We can see this at play with the following schemas:

components:
  schemas:
    Client:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        id:
          type: number
    ClientWithExtension:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        id:
          type: number
          x-go-type-skip-optional-pointer: true

From here, we now get two different models:

// Client defines model for Client.
type Client struct {
	Id   *float32 `json:"id,omitempty"`
	Name string   `json:"name"`
}

// ClientWithExtension defines model for ClientWithExtension.
type ClientWithExtension struct {
	Id   float32 `json:"id,omitempty"`
	Name string  `json:"name"`
}

You can see this in more detail in the example code.

x-go-name

Override the generated name of a type

By default, oapi-codegen will attempt to generate the name of types in as best a way it can.

However, sometimes, the name doesn't quite fit what your codebase standards are, or the intent of the field, so you can override it with x-go-name.

We can see this at play with the following schemas:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: x-go-name
components:
  schemas:
    Client:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        id:
          type: number
    ClientWithExtension:
      type: object
      # can be used on a type
      x-go-name: ClientRenamedByExtension
      required:
        - name
      properties:
        name:
          type: string
        id:
          type: number
	  # or on a field
          x-go-name: AccountIdentifier

From here, we now get two different models:

// Client defines model for Client.
type Client struct {
	Id   *float32 `json:"id,omitempty"`
	Name string   `json:"name"`
}

// ClientRenamedByExtension defines model for ClientWithExtension.
type ClientRenamedByExtension struct {
	AccountIdentifier *float32 `json:"id,omitempty"`
	Name              string   `json:"name"`
}

You can see this in more detail in the example code.

x-omitempty

Force the presence of the JSON tag `omitempty` on a field

In a case that you may want to add the JSON struct tag omitempty to types that don't have one generated by default - for instance a required field - you can use the x-omitempty extension.

We can see this at play with the following schemas:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: x-omitempty
components:
  schemas:
    Client:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        id:
          type: number
    ClientWithExtension:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          # for some reason, you may want this behaviour, even though it's a required field
          x-omitempty: true
        id:
          type: number

From here, we now get two different models:

// Client defines model for Client.
type Client struct {
	Id   *float32 `json:"id,omitempty"`
	Name string   `json:"name"`
}

// ClientWithExtension defines model for ClientWithExtension.
type ClientWithExtension struct {
	Id   *float32 `json:"id,omitempty"`
	Name string   `json:"name,omitempty"`
}

Notice that the ComplexField is still generated in full, but the type will then be ignored with JSON marshalling.

You can see this in more detail in the example code.

x-go-json-ignore

When (un)marshaling JSON, ignore field(s)

By default, oapi-codegen will generate json:"..." struct tags for all fields in a struct, so JSON (un)marshaling works.

However, sometimes, you want to omit fields, which can be done with the x-go-json-ignore extension.

We can see this at play with the following schemas:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: x-go-json-ignore
components:
  schemas:
    Client:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        complexField:
          type: object
          properties:
            name:
              type: string
            accountName:
              type: string
          # ...
    ClientWithExtension:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        complexField:
          type: object
          properties:
            name:
              type: string
            accountName:
              type: string
          # ...
          x-go-json-ignore: true

From here, we now get two different models:

// Client defines model for Client.
type Client struct {
	ComplexField *struct {
		AccountName *string `json:"accountName,omitempty"`
		Name        *string `json:"name,omitempty"`
	} `json:"complexField,omitempty"`
	Name string `json:"name"`
}

// ClientWithExtension defines model for ClientWithExtension.
type ClientWithExtension struct {
	ComplexField *struct {
		AccountName *string `json:"accountName,omitempty"`
		Name        *string `json:"name,omitempty"`
	} `json:"-"`
	Name string `json:"name"`
}

Notice that the ComplexField is still generated in full, but the type will then be ignored with JSON marshalling.

You can see this in more detail in the example code.

x-oapi-codegen-extra-tags

Generate arbitrary struct tags to fields

If you're making use of a field's struct tags to i.e. apply validation, decide whether something should be logged, etc, you can use x-oapi-codegen-extra-tags to set additional tags for your generated types.

We can see this at play with the following schemas:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: x-oapi-codegen-extra-tags
components:
  schemas:
    Client:
      type: object
      required:
        - name
	- id
      properties:
        name:
          type: string
        id:
          type: number
    ClientWithExtension:
      type: object
      required:
        - name
	- id
      properties:
        name:
          type: string
        id:
          type: number
          x-oapi-codegen-extra-tags:
            validate: "required,min=1,max=256"
            safe-to-log: "true"
            gorm: primarykey

From here, we now get two different models:

// Client defines model for Client.
type Client struct {
	Id   float32 `json:"id"`
	Name string  `json:"name"`
}

// ClientWithExtension defines model for ClientWithExtension.
type ClientWithExtension struct {
	Id   float32 `gorm:"primarykey" json:"id" safe-to-log:"true" validate:"required,min=1,max=256"`
	Name string  `json:"name"`
}

You can see this in more detail in the example code.

x-enum-varnames / x-enumNames

Override generated variable names for enum constants

When consuming an enum value from an external system, the name may not produce a nice variable name. Using the x-enum-varnames extension allows overriding the name of the generated variable names.

We can see this at play with the following schemas:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: x-enumNames and x-enum-varnames
components:
  schemas:
    ClientType:
      type: string
      enum:
        - ACT
        - EXP
    ClientTypeWithNamesExtension:
      type: string
      enum:
        - ACT
        - EXP
      x-enumNames:
        - Active
        - Expired
    ClientTypeWithVarNamesExtension:
      type: string
      enum:
        - ACT
        - EXP
      x-enum-varnames:
        - Active
        - Expired

From here, we now get two different forms of the same enum definition.

// Defines values for ClientType.
const (
	ACT ClientType = "ACT"
	EXP ClientType = "EXP"
)

// ClientType defines model for ClientType.
type ClientType string

// Defines values for ClientTypeWithExtension.
const (
	Active  ClientTypeWithExtension = "ACT"
	Expired ClientTypeWithExtension = "EXP"
)

// ClientTypeWithExtension defines model for ClientTypeWithExtension.
type ClientTypeWithExtension string

You can see this in more detail in the example code.

x-deprecated-reason

Add a GoDoc deprecation warning to a type

When an OpenAPI type is deprecated, a deprecation warning can be added in the GoDoc using x-deprecated-reason.

We can see this at play with the following schemas:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: x-deprecated-reason
components:
  schemas:
    Client:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        id:
          type: number
    ClientWithExtension:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          deprecated: true
          x-deprecated-reason: Don't use because reasons
        id:
          type: number
          # NOTE that this doesn't generate, as no `deprecated: true` is set
          x-deprecated-reason: NOTE you shouldn't see this, as you've not deprecated this field

From here, we now get two different forms of the same enum definition.

// Client defines model for Client.
type Client struct {
	Id   *float32 `json:"id,omitempty"`
	Name string   `json:"name"`
}

// ClientWithExtension defines model for ClientWithExtension.
type ClientWithExtension struct {
	Id *float32 `json:"id,omitempty"`
	// Deprecated: Don't use because reasons
	Name string `json:"name"`
}

Notice that because we've not set deprecated: true to the name field, it doesn't generate a deprecation warning.

You can see this in more detail in the example code.

x-order

Explicitly order struct fields

Whether you like certain fields being ordered before others, or you want to perform more efficient packing of your structs, the x-order extension is here for you.

Note that x-order is 1-indexed - x-order: 0 is not a valid value.

When an OpenAPI type is deprecated, a deprecation warning can be added in the GoDoc using x-deprecated-reason.

We can see this at play with the following schemas:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: x-order
components:
  schemas:
    Client:
      type: object
      required:
        - name
      properties:
        a_name:
          type: string
        id:
          type: number
    ClientWithExtension:
      type: object
      required:
        - name
      properties:
        a_name:
          type: string
          x-order: 2
        id:
          type: number
          x-order: 1

From here, we now get two different forms of the same type definition.

// Client defines model for Client.
type Client struct {
	AName *string  `json:"a_name,omitempty"`
	Id    *float32 `json:"id,omitempty"`
}

// ClientWithExtension defines model for ClientWithExtension.
type ClientWithExtension struct {
	Id    *float32 `json:"id,omitempty"`
	AName *string  `json:"a_name,omitempty"`
}

You can see this in more detail in the example code.

Request/response validation middleware

The generated code that oapi-codegen produces has some validation for some incoming data, such as checking for required headers, and when using the strict server you get some more validation around the correct usage of the response types.

However, this leaves a lot of validation that needs to be done, which can be tedious to hand-write this logic, especially for large or complex OpenAPI specifications.

To simplify this, we use a middleware, which provides the request validation. The middleware you want to use depends on the server you're using:

Server Middleware library

Chi

nethttp-middleware

Echo

echo-middleware

Fiber

fiber-middleware

Gin

gin-middleware

gorilla/mux

nethttp-middleware

Iris

iris-middleware

1.22+ net/http

nethttp-middleware

Note

It is not currently possible to validate the HTTP response with a middleware.

Note

We're also exploring the use of libopenapi-validator for request/response validation middleware

Implementing security

If you're using a specification with Security Schemes and Security Requirements, you'll want to authenticate and authorize requests.

On the server

Note

Out-of-the-box, the server-side code generated by oapi-codegen does not provide security validation.

To perform authentication, you will need to use the validation middleware.

In the future, we plan to implement server-side validation in the generated code

To see how this can work, check out the authenticated API example.

On the client

With a generated client, you'll want to use the client's generated WithRequestEditorFn function to pass in a given request editor RequestEditorFn.

For instance:

import (
	"context"
	"fmt"
	"log"

	"github.com/deepmap/oapi-codegen/v2/pkg/securityprovider"
)

func main() {
	basicAuth, err := securityprovider.NewSecurityProviderBasicAuth("my_user", "my_pass")
	if err != nil {
		log.Fatal(err)
	}

	client, err := NewClient("https://....", WithRequestEditorFn(basicAuth.Intercept))
	if err != nil {
		log.Fatal(err)
	}

	resp, err := client.GetClient(context.TODO())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("resp.StatusCode: %v\n", resp.StatusCode)
}

Notice that we're using a pre-built provider from the pkg/securityprovider package, which has some inbuilt support for other types of authentication, too.

Custom code generation

It is possible to extend the inbuilt code generation from oapi-codegen using Go's text/templates.

You can specify, through your configuration file, the output-options.user-templates setting to override the inbuilt templates and use a user-defined template.

Note

Filenames given to the user-templates configuration must exactly match the filename that oapi-codegen is looking for

Local paths

Within your configuration file, you can specify relative or absolute paths to a file to reference for the template, such as:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
# ...
output-options:
  user-templates:
    client-with-responses.tmpl: ./custom-template.tmpl
    additional-properties.tmpl: /tmp/foo.bar
    typedef.tmpl: no-prefix.tmpl

[!WARN] We do not interpolate ~ or $HOME (or other environment variables) in paths given

HTTPS paths

It is also possible to use HTTPS URLs.

Warning

Although possible, this does lead to oapi-codegen executions not necessarily being reproducible. It's recommended to vendor (copy) the OpenAPI spec into your codebase and reference it locally

This will be disabled by default (but possible to turn back on via configuration) in the future

To use it, you can use the following configuration:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
# ...
output-options:
  user-templates:
    # The following are referencing a version of the default client-with-responses.tmpl file, but loaded in through GitHub's raw.githubusercontent.com. The general form to use raw.githubusercontent.com is as follows https://raw.githubusercontent.com/<username>/<project>/<commitish>/path/to/template/template.tmpl

    # Alternatively using raw.githubusercontent.com with a hash
    client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/ad5eada4f3ccc28a88477cef62ea21c17fc8aa01/pkg/codegen/templates/client-with-responses.tmpl
    # Alternatively using raw.githubusercontent.com with a tag
    client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/v2.1.0/pkg/codegen/templates/client-with-responses.tmpl
    # Alternatively using raw.githubusercontent.com with a branch
    client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/master/pkg/codegen/templates/client-with-responses.tmpl

Warning

If using URLs that pull locations from a Git repo, such as raw.githubusercontent.com, it is strongly encouraged to use a tag or a raw commit hash instead of a branch like main. Tracking a branch can lead to unexpected API drift, and loss of the ability to reproduce a build.

Inline template

It's also possible to set the templates inline in the configuration file:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
# ...
output-options:
  user-templates:
    # NOTE the use of the `|` (pipe symbol) here to denote that this is a
    # multi-line statement that should preserve newlines. More reading:
    # https://stackoverflow.com/a/18708156/2257038 and
    # https://stackoverflow.com/a/15365296/2257038
    client-with-responses.tmpl: |
        // ClientWithResponses builds on ClientInterface to offer response payloads
        type ClientWithResponses struct {
            ClientInterface
        }
        ...

Using the Go package

Alternatively, you are able to use the underlying code generation as a package, which will be documented in the future.

Additional Properties (additionalProperties)

OpenAPI Schemas implicitly accept additionalProperties, meaning that any fields provided, but not explicitly defined via properties on the schema are accepted as input, and propagated. When unspecified, OpenAPI defines that the additionalProperties field is assumed to be true.

For simplicity, and to remove a fair bit of duplication and boilerplate, oapi-codegen decides to ignore the implicit additionalProperties: true, and instead requires you to specify the additionalProperties key to generate the boilerplate.

Note

In the future this will be possible to disable this functionality, and honour the implicit additionalProperties: true

Below you can see some examples of how additionalProperties affects the generated code.

Implicit additionalProperties: true / no additionalProperties set

components:
  schemas:
    Thing:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
      # implicit additionalProperties: true

Will generate:

// Thing defines model for Thing.
type Thing struct {
	Id int `json:"id"`
}

// with no generated boilerplate nor the `AdditionalProperties` field

Explicit additionalProperties: true

components:
  schemas:
    Thing:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
      # explicit true
      additionalProperties: true

Will generate:

// Thing defines model for Thing.
type Thing struct {
	Id                   int                    `json:"id"`
	AdditionalProperties map[string]interface{} `json:"-"`
}

// with generated boilerplate below
Boilerplate
// Getter for additional properties for Thing. Returns the specified
// element and whether it was found
func (a Thing) Get(fieldName string) (value interface{}, found bool) {
	if a.AdditionalProperties != nil {
		value, found = a.AdditionalProperties[fieldName]
	}
	return
}

// Setter for additional properties for Thing
func (a *Thing) Set(fieldName string, value interface{}) {
	if a.AdditionalProperties == nil {
		a.AdditionalProperties = make(map[string]interface{})
	}
	a.AdditionalProperties[fieldName] = value
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a *Thing) UnmarshalJSON(b []byte) error {
	object := make(map[string]json.RawMessage)
	err := json.Unmarshal(b, &object)
	if err != nil {
		return err
	}

	if raw, found := object["id"]; found {
		err = json.Unmarshal(raw, &a.Id)
		if err != nil {
			return fmt.Errorf("error reading 'id': %w", err)
		}
		delete(object, "id")
	}

	if len(object) != 0 {
		a.AdditionalProperties = make(map[string]interface{})
		for fieldName, fieldBuf := range object {
			var fieldVal interface{}
			err := json.Unmarshal(fieldBuf, &fieldVal)
			if err != nil {
				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
			}
			a.AdditionalProperties[fieldName] = fieldVal
		}
	}
	return nil
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a Thing) MarshalJSON() ([]byte, error) {
	var err error
	object := make(map[string]json.RawMessage)

	object["id"], err = json.Marshal(a.Id)
	if err != nil {
		return nil, fmt.Errorf("error marshaling 'id': %w", err)
	}

	for fieldName, field := range a.AdditionalProperties {
		object[fieldName], err = json.Marshal(field)
		if err != nil {
			return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
		}
	}
	return json.Marshal(object)
}

additionalProperties as integers

components:
  schemas:
    Thing:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
      # simple type
      additionalProperties:
        type: integer

Will generate:

// Thing defines model for Thing.
type Thing struct {
	Id                   int            `json:"id"`
	AdditionalProperties map[string]int `json:"-"`
}

// with generated boilerplate below
Boilerplate
// Getter for additional properties for Thing. Returns the specified
// element and whether it was found
func (a Thing) Get(fieldName string) (value int, found bool) {
	if a.AdditionalProperties != nil {
		value, found = a.AdditionalProperties[fieldName]
	}
	return
}

// Setter for additional properties for Thing
func (a *Thing) Set(fieldName string, value int) {
	if a.AdditionalProperties == nil {
		a.AdditionalProperties = make(map[string]int)
	}
	a.AdditionalProperties[fieldName] = value
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a *Thing) UnmarshalJSON(b []byte) error {
	object := make(map[string]json.RawMessage)
	err := json.Unmarshal(b, &object)
	if err != nil {
		return err
	}

	if raw, found := object["id"]; found {
		err = json.Unmarshal(raw, &a.Id)
		if err != nil {
			return fmt.Errorf("error reading 'id': %w", err)
		}
		delete(object, "id")
	}

	if len(object) != 0 {
		a.AdditionalProperties = make(map[string]int)
		for fieldName, fieldBuf := range object {
			var fieldVal int
			err := json.Unmarshal(fieldBuf, &fieldVal)
			if err != nil {
				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
			}
			a.AdditionalProperties[fieldName] = fieldVal
		}
	}
	return nil
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a Thing) MarshalJSON() ([]byte, error) {
	var err error
	object := make(map[string]json.RawMessage)

	object["id"], err = json.Marshal(a.Id)
	if err != nil {
		return nil, fmt.Errorf("error marshaling 'id': %w", err)
	}

	for fieldName, field := range a.AdditionalProperties {
		object[fieldName], err = json.Marshal(field)
		if err != nil {
			return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
		}
	}
	return json.Marshal(object)
}

additionalProperties with an object

components:
  schemas:
    Thing:
      type: object
      required:
        - id
      properties:
        id:
          type: integer
      # object
      additionalProperties:
        type: object
        properties:
          foo:
            type: string

Will generate:

// Thing defines model for Thing.
type Thing struct {
	Id                   int `json:"id"`
	AdditionalProperties map[string]struct {
		Foo *string `json:"foo,omitempty"`
	} `json:"-"`
}

// with generated boilerplate below
Boilerplate
// Getter for additional properties for Thing. Returns the specified
// element and whether it was found
func (a Thing) Get(fieldName string) (value struct {
	Foo *string `json:"foo,omitempty"`
}, found bool) {
	if a.AdditionalProperties != nil {
		value, found = a.AdditionalProperties[fieldName]
	}
	return
}

// Setter for additional properties for Thing
func (a *Thing) Set(fieldName string, value struct {
	Foo *string `json:"foo,omitempty"`
}) {
	if a.AdditionalProperties == nil {
		a.AdditionalProperties = make(map[string]struct {
			Foo *string `json:"foo,omitempty"`
		})
	}
	a.AdditionalProperties[fieldName] = value
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a *Thing) UnmarshalJSON(b []byte) error {
	object := make(map[string]json.RawMessage)
	err := json.Unmarshal(b, &object)
	if err != nil {
		return err
	}

	if raw, found := object["id"]; found {
		err = json.Unmarshal(raw, &a.Id)
		if err != nil {
			return fmt.Errorf("error reading 'id': %w", err)
		}
		delete(object, "id")
	}

	if len(object) != 0 {
		a.AdditionalProperties = make(map[string]struct {
			Foo *string `json:"foo,omitempty"`
		})
		for fieldName, fieldBuf := range object {
			var fieldVal struct {
				Foo *string `json:"foo,omitempty"`
			}
			err := json.Unmarshal(fieldBuf, &fieldVal)
			if err != nil {
				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
			}
			a.AdditionalProperties[fieldName] = fieldVal
		}
	}
	return nil
}

// Override default JSON handling for Thing to handle AdditionalProperties
func (a Thing) MarshalJSON() ([]byte, error) {
	var err error
	object := make(map[string]json.RawMessage)

	object["id"], err = json.Marshal(a.Id)
	if err != nil {
		return nil, fmt.Errorf("error marshaling 'id': %w", err)
	}

	for fieldName, field := range a.AdditionalProperties {
		object[fieldName], err = json.Marshal(field)
		if err != nil {
			return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
		}
	}
	return json.Marshal(object)
}

Examples

The examples directory contains some additional cases which are useful examples for how to use oapi-codegen, including how you'd take the Petstore API and implement it with oapi-codegen.

You could also find some cases of how the project can be used by checking out our internal test cases which are real-world usages that make up our regression tests.

Blog posts

We love reading posts by the community about how to use the project.

Here are a few we've found around the Web:

Got one to add? Please raise a PR!

Frequently Asked Questions (FAQs)

How does oapi-codegen handle anyOf, allOf and oneOf?

oapi-codegen supports anyOf, allOf and oneOf for generated code.

For instance, through the following OpenAPI spec:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Using complex schemas
  description: An example of `anyOf`, `allOf` and `oneOf`
components:
  schemas:
    # base types
    Client:
      type: object
      required:
        - name
      properties:
        name:
          type: string
    Identity:
      type: object
      required:
        - issuer
      properties:
        issuer:
          type: string

    # allOf performs a union of all types defined
    ClientWithId:
      allOf:
        - $ref: '#/components/schemas/Client'
        - properties:
            id:
              type: integer
          required:
            - id

    # allOf performs a union of all types defined, but if there's a duplicate field defined, it'll be overwritten by the last schema
    # https://github.com/deepmap/oapi-codegen/issues/1569
    IdentityWithDuplicateField:
      allOf:
        # `issuer` will be ignored
        - $ref: '#/components/schemas/Identity'
        # `issuer` will be ignored
        - properties:
            issuer:
              type: integer
        # `issuer` will take precedence
        - properties:
            issuer:
              type: object
              properties:
                name:
                  type: string
              required:
                - name

    # anyOf results in a type that has an `AsClient`/`MergeClient`/`FromClient` and an `AsIdentity`/`MergeIdentity`/`FromIdentity` method so you can choose which of them you want to retrieve
    ClientAndMaybeIdentity:
      anyOf:
        - $ref: '#/components/schemas/Client'
        - $ref: '#/components/schemas/Identity'

    # oneOf results in a type that has an `AsClient`/`MergeClient`/`FromClient` and an `AsIdentity`/`MergeIdentity`/`FromIdentity` method so you can choose which of them you want to retrieve
    ClientOrIdentity:
      oneOf:
        - $ref: '#/components/schemas/Client'
        - $ref: '#/components/schemas/Identity'

This results in the following types:

Base types
// Client defines model for Client.
type Client struct {
	Name string `json:"name"`
}

// Identity defines model for Identity.
type Identity struct {
	Issuer string `json:"issuer"`
}
allOf
// ClientWithId defines model for ClientWithId.
type ClientWithId struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
}

// IdentityWithDuplicateField defines model for IdentityWithDuplicateField.
type IdentityWithDuplicateField struct {
	Issuer struct {
		Name string `json:"name"`
	} `json:"issuer"`
}
anyOf
import (
	"encoding/json"

	"github.com/oapi-codegen/runtime"
)

// ClientAndMaybeIdentity defines model for ClientAndMaybeIdentity.
type ClientAndMaybeIdentity struct {
	union json.RawMessage
}

// AsClient returns the union data inside the ClientAndMaybeIdentity as a Client
func (t ClientAndMaybeIdentity) AsClient() (Client, error) {
	var body Client
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromClient overwrites any union data inside the ClientAndMaybeIdentity as the provided Client
func (t *ClientAndMaybeIdentity) FromClient(v Client) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeClient performs a merge with any union data inside the ClientAndMaybeIdentity, using the provided Client
func (t *ClientAndMaybeIdentity) MergeClient(v Client) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

// AsIdentity returns the union data inside the ClientAndMaybeIdentity as a Identity
func (t ClientAndMaybeIdentity) AsIdentity() (Identity, error) {
	var body Identity
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromIdentity overwrites any union data inside the ClientAndMaybeIdentity as the provided Identity
func (t *ClientAndMaybeIdentity) FromIdentity(v Identity) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeIdentity performs a merge with any union data inside the ClientAndMaybeIdentity, using the provided Identity
func (t *ClientAndMaybeIdentity) MergeIdentity(v Identity) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

func (t ClientAndMaybeIdentity) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

func (t *ClientAndMaybeIdentity) UnmarshalJSON(b []byte) error {
	err := t.union.UnmarshalJSON(b)
	return err
}
oneOf
// AsClient returns the union data inside the ClientOrIdentity as a Client
func (t ClientOrIdentity) AsClient() (Client, error) {
	var body Client
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromClient overwrites any union data inside the ClientOrIdentity as the provided Client
func (t *ClientOrIdentity) FromClient(v Client) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeClient performs a merge with any union data inside the ClientOrIdentity, using the provided Client
func (t *ClientOrIdentity) MergeClient(v Client) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

// AsIdentity returns the union data inside the ClientOrIdentity as a Identity
func (t ClientOrIdentity) AsIdentity() (Identity, error) {
	var body Identity
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromIdentity overwrites any union data inside the ClientOrIdentity as the provided Identity
func (t *ClientOrIdentity) FromIdentity(v Identity) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeIdentity performs a merge with any union data inside the ClientOrIdentity, using the provided Identity
func (t *ClientOrIdentity) MergeIdentity(v Identity) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

func (t ClientOrIdentity) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

func (t *ClientOrIdentity) UnmarshalJSON(b []byte) error {
	err := t.union.UnmarshalJSON(b)
	return err
}

For more info, check out the example code.

How can I ignore parts of the spec I don't care about?

By default, oapi-codegen will generate everything from the specification.

If you'd like to reduce what's generated, you can use one of a few options in the configuration file to tune the generation of the resulting output:

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
output-options:
  include-tags: []
  exclude-tags: []
  include-operation-ids: []
  exclude-operation-ids: []
  exclude-schemas: []

Check the docs for more details of usage.

Should I commit the generated code?

We recommend doing so, yes, for the following reasons:

  • It means it's easier to view the impact of a change - be it due to an upgrade of oapi-codegen, or a change to your spec - and has helped catch (possibly) breaking changes in the past more easily
  • It then allows your codebase to be consumed as a library, as all the files are committed

This means you'll need to have your CI/CD pipeline validate that generated files are all up-to-date, but that's a fairly straightforward piece of work.

Should I lint the generated code?

We really ask that you don't. Although it intends to be idiomatic Go code, it's not expected to pass all the various linting rules that your project may apply.

Note

We will, on occasion, improve the generated code to fix some linting warnings, such as those from go vet, but this should not be an expected change.

I've just updated my version of kin-openapi, and now I can't build my code ๐Ÿ˜ 

The kin-openapi project - which we ๐Ÿ’œ for providing a great library and set of tooling for interacting with OpenAPI - is a pre-v1 release, which means that they're within their rights to push breaking changes.

This may lead to breakage in your consuming code, and if so, sorry that's happened!

We'll be aware of the issue, and will work to update both the core oapi-codegen and the middlewares accordingly.

oapi-codegen's People

Contributors

alexandear avatar bvwells avatar chrisgacsal avatar chrusty avatar dannymidnight avatar deepmap-marcinr avatar dependabot[bot] avatar derfenix avatar dududko avatar gitu avatar jamietanna avatar jleagle avatar jmcnevin avatar johanneswuerbach avatar masu-mi avatar mycreepy avatar nandedamana avatar natsukagami avatar pseudo-su avatar qmuntal avatar reinkrul avatar renovate[bot] avatar rkojedzinszky avatar shouheinishi avatar stevenh avatar tfaller avatar wangyoucao577 avatar warboss-rus avatar weitzj avatar wolfeidau avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oapi-codegen's Issues

Invalid character in function name

Hey all,

we have a special openapi definition which contains the following:

  /customer:
    post:
      summary: Create New Customer.
      operationId: customer-fn-create

This will fail with:

$ oapi-codegen -generate types spec.yaml > gen.go
error generating code: error formatting Go code: 158:14: expected type, found '-' (and 3 more errors)

As the generated code will be

// customer-fn-createJSONBody defines parameters for CustomerFnCreate.
type customer-fn-createJSONBody CustomerRequest

What do you think about auto resolving this issue? Just omit invalid characters in the generated names?

Regards,
Carsten

Generator error on string format

While working with a spec that had a parameter like below the generator would error.

uuid: 
  type: string
  format: uuid
  description: A unique identifier.
  example: 32b1b767-c1fe-4540-9bc3-b3a51fc4a0b7
$ oapi-codegen ./spec.yaml 
Error generating server stubs: error generating Go types for component schemas: error converting Schema Foo to Go type: error generating type for property 'uuid': invalid string format: uuid

The error is generated here

case "string":
switch f {
case "", "password":
result = "string"
case "date-time", "date":
result = "time.Time"
default:
return "", fmt.Errorf("invalid string format: %s", f)

In a comment here it's referencing https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#dataTypes but it's not following the spec correctly

Also from
https://swagger.io/docs/specification/data-models/data-types/#format

However, to support documentation needs, the format property is an open string-valued property, and can have any value. Formats such as "email", "uuid", and so on, MAY be used even though undefined by this specification. Types that are not accompanied by a format property follow the type definition in the JSON Schema.

Where the default behavior is defined

Tools that do not recognize a specific format MAY default back to the type alone, as if the format is not specified.

So the default case should be

result = "string"

Remove hidden byte-order-marks (BOM) in generated code

Given some weird schemas with weird descriptions (i.e. a description, which gets autogenerated and filled via a CMS), one might end up with BOM (byte-order-marks) inside the []byte buffer.

The Go-Compiler is not happy with BOM. Therefore the generated Go-Code has to be cleaned up.

This could be done using awk:

 awk '{ gsub(/\xef\xbb\xbf/,""); print }' inputFile > outputFile

A better way, would be to add this cleanup right before one writes the generated Go-Code to disk.

Allow specifying a `skip-fmt` cli-param to debug generated code

Since there is a bunch of weird specs out there, the generated code sometimes fails.
I would like to debug, what is either wrong in the spec or how the generator can be made more robust.

The idea would be to add a skip-fmt option to the generator. This way the current behaviour is preserved, whilst one can allow skipping the fmt step.

Possible to split up ServerInterface

First of all thanks for this library ๐Ÿ˜„

After playing around with it for a while I experience a practical problem. The ServerInterface represents an interface for all serverHandlers. For quick prototyping this works well, however it becomes hard to use when organizing code based on entities.

For example, how would I use the registerHandlers correctly in this case:

type Project struct {
	r *ProjectRepo
}

func (p *Project) CreateProject(ctx Echo.Context) error {
        // non working repo insert
	r.Insert()

	return ctx.JSON(http.StatusOK, "")
}

type User struct {
	r *UserRepo
}

func (u *User) CreateUser(ctx Echo.Context) error {
        // non working repo insert
	r.Insert()
	return ctx.JSON(http.StatusOK, "")
}

e := echo.New()
// Now User and Project implement only a small part of the ServerInterface. And the
// RegisterHandlers would fail.
api.RegisterHandlers(e, ??)

How would we solve this issue? Could a solution be to register multiple (namespaces) handlers?

uint64 support

Currently working on a crypto project and using this tech for a public API. Lot of crypto data is in uint64 and it would be great to have this supported via the schemas like so?

StakeUnits:
          type: integer
          format: uint64

Reserved golang keywords in spec cause errors

I have a type parameter in my spec as follows:

/animal/{type}:
    get:
      summary: Get an animal by type
      parameters:
        - name: type
          in: path
          required: true
          schema:
            type: string

Which resuls in the following server interface:

type ServerInterface interface {
  GetAnimalByType(ctx echo.Context, type string, params GetAnimalByTypeParams) error
}

But as you can see this results in a parameter named type which is a reseverd golang keyword.

Perhaps pre/post fixing all param names can prevent these errors.

optional bson mapping when working with mongo

It would be amazing if we could have additional anotations to be generated in our interface for certain fields.
For example, when working with mongo we need to parse the field _id, in that case it would be nice to add the special bson:"_id" annotation for the id field in our interface.

No error on empty operationId

It took me a while to figure out why the generated functions did not have a name and the output of the tool was something like the following:

error generating code: error formatting Go code: 201:1: expected '}', found '(' (and 10 more errors)

It turns out the operationId was not set. Adding a check might help the users prevent this mistake.

StyleParam on objects with pointer fields not supported

When passing an object to runtime.StyleParam that includes pointer field the following error is returned:
error formatting 'struct_field': unsupported type *string

This can be reproduced by adding an optional field in styleparam_test.go:

type TestObject struct {
	FirstName string  `json:"firstName"`
	LastName  *string `json:"lastName,omitempty"`
	Role      string  `json:"role"`
}
ln := "Johnson"
object := TestObject{
	FirstName: "Alex",
	LastName:  &ln,
	Role:      "admin",
}

I'm guessing the easiest fix would be to add a case in primitiveToString for pointers or maybe dereferencing it before going in to the switch.

Type name hints via extensions

Schemas, Operations, support Swagger extensions. Rather than inferring Go type names from those properties, we can also allow specifying them. Adding support for an extension like x-go-typename on those would allow for more flexibility in naming the Swagger properties more clearly since they don't have to map to the same Go type.

Required and empty arrays are serialized with null values

Due to the default behaviour of the JSON serializer, an empty array gets serialized to value null.

type foo struct {
  bar []string
}

Resulting json

{
  "bar": null
}

See the following issue for indept discussion: golang/go#27589

Before d2cebc7, required arrays also got the omitempty tag. Although not perfect, that did the trick for us.

Would you consider adding the omitempty tag back to required arrays while the golang team is discussing options?

feature request: GetSwaggerUi()

I'm currently using the following code generation:

// go:generate oapi-codegen --package=pkg --generate spec -o ./pkg/spec.gen.go ./openapi.yaml

I'm curious if you'd be open to adding the ability to embed the swagger-ui html file into the code generated by oapi-codegen.

What would be nice for my use case is if there was a GetSwaggerUI() alongside GetSwagger().

Add documentation for request validation

First of all, thank you all for the work you are putting into this project.

I am currently evaluating this for a project of mine. Reading through #54 I found out that validation can be achieved using kin-openapi's openapi3filter.
I think it would be useful to document this in the main README, maybe even with an example.

Client implantation example

Hey be great to have a client implantation in the examples too. This would be a big help for dev's like me that are still somewhat new to golang. Thanks

Ideas about new functions: chi support, request/response validation

I have some ideas to new functions and I am ready to code them.

  1. Add command line option to produce chi compatible server interface and handlers.
  2. Add support for full request validation.
    a) add middleware for chi router with params validation and secure validation;
    b) add secure validation to echo middleware.

For security validation there is needed for "AuthenticationFunc". I prefer to add it not as callback function, but as interface function.

  1. Add support for full response validation. There is two options.

a) validation may be added as on runtime basis as middleware: get generated response and validate it with openapi3filter. It is simple, but adds time to request processing;

b) static validation. We can generate boilerplate, so interface functions will be returns predefined genereated structs from boilerplate, these struct will be self-validated and produce from them json responses. It is more complicated, but will be more user-friendly to developer and gets better perfomance.

Please, say your opinion about this features.

Generator error: Client responses with body

The return type in the client is (*http.Response, error)

func (c *Client) {{$opid}}(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}, body {{if not .GetBodyDefinition.Required}}*{{end}}{{if .GetBodyDefinition.CustomType}}{{$opid}}RequestBody{{else}}{{.GetBodyDefinition.TypeDef}}{{end}}) (*http.Response, error){

While the interface is always expecting error

{{.OperationId}}(ctx echo.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error

I recommend adding this

// Compile time check to ensure the client satisfies the server interface
var _ ServerInterface = (*Client)(nil)

to the top of

// A client which conforms to the OpenAPI3 specification for this service. The

https://medium.com/@matryer/golang-tip-compile-time-checks-to-ensure-your-type-satisfies-an-interface-c167afed3aae

client response parsing needs cleanup

The client response parsing is now out of date with the code generation, since it doesn't use the templates which operate on internal models. It needs to be rewritten to generate all the code from the OperationDefinitions[] based input, like the server and client code.

Support for type: object and {}

This project is great, glad I found it. Noticed this running against my own project:

The Java OpenAPI Tools code generator templates for go support type: object and Any Type ({} in OpenApi syntax) types, which I believe should just translate to map[string]interface{} and interface{} respectively, I think.

object just errors out in the current oapi-codegen, and using {} results in an empty anonymous struct type, which isn't quite right.

Add generated code comments

As defined in this proposal.

All that's needed is to add comments to generated code matching ^// Code generated .* DO NOT EDIT\.$

Generate default operationId if none provided in spec

Is it possible to create a default operationId using a combination of the Verb & Path if the operationId is not provided in the spec? More often than not the author of the original spec will use exactly that semantic to generate the operationId name. Rather than error out here just generate a default name?

The scenario I am faced is that a lot of the legacy specs, in my organization, in heavy use were authored without the need for operationId (since the codegen for most of the code only generated types). If this could be supported, that would be great IMO.

Better swagger spec validation

It's easy to make structural errors in swagger which still parse, but affect the output. On errors, we typically end up with some of the swagger spec parsed into the ExtensionProps members where they exist.

Validating these to ensure they only contain things of the form "x-.*" will catch many errors.

Options for supporting anyOf or oneOf

Our organization is looking at using oapi-codegen and we have a need to support oneOf and are looking into a few potential ways to do so. I want to get feedback about which best fits into the oapi-codegen vision.

First of all, there would need to be discriminators used for any polymorphic objects (https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism/).

With that in mind this is my proposal that I will implement if it looks good:

for the example spec (fragment):

paths: 
  /mything:
    put:
      summary: Put my thing
      operationId: putMyThing
      requestBody:
        description: Contents of thing
        required: true
        content:
          application-json:
            schema:
              discriminator:
                 propertyName: thingType
              oneOf:
                - $ref: "#/components/schemas/EasyThing"
                - $ref: "#/components/schemas/HardThing"

would generate an interface with

type ServerInterface interface {
	// Put my thing// (PUT /mything)
	PutMyThing(ctx echo.Context, discriminator string) error
}

Then the user could use the information gleaned from the discriminator to do something like:

m := make(map[string]interface{})
err := json.Unmarshal(ctx.Request().Body, &m)
switch m[discriminator] {
	case "easyThing":
		{
			doEasyThingStuff(ctx,m)
		}
	case "hardThing":
		{
			doHardThingStuff(ctx,m)
		}
}

Stack overflow with recursive types

I'm creating an OpenAPI specification for the Google Firestore REST interface. This has some recursive types, which causes a stack overflow error using this tool.

Here's a sample YAML, based loosely on some of the Firestore data types:

openapi: 3.0.2
info:
  version: '0.0.1'
  title: example

paths:
  /example:
    get:
      operationId: exampleGet
      responses:
        '200':
          description: "OK"
          content:
            'application/json':
              schema:
                $ref: '#/components/schemas/Document'

components:
  schemas:
    Document:
      type: object
      properties:
        fields:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/Value'

    Value:
      type: object
      properties:
        stringValue:
          type: string
        arrayValue:
          $ref: '#/components/schemas/ArrayValue'

    ArrayValue:
      type: array
      items:
        $ref: '#/components/schemas/Value'

Running this through the generator yields:

Error output ``` runtime: goroutine stack exceeds 1000000000-byte limit fatal error: stack overflow

runtime stack:
runtime.throw(0x14698c7, 0xe)
/usr/local/Cellar/go/1.11.5/libexec/src/runtime/panic.go:608 +0x72
runtime.newstack()
/usr/local/Cellar/go/1.11.5/libexec/src/runtime/stack.go:1008 +0x729
runtime.morestack()
/usr/local/Cellar/go/1.11.5/libexec/src/runtime/asm_amd64.s:429 +0x8f

goroutine 1 [running]:
strings.Count(0xc000020dc0, 0x1a, 0x1465e06, 0x1, 0x0)
/usr/local/Cellar/go/1.11.5/libexec/src/strings/strings.go:78 +0x141 fp=0xc020d8e350 sp=0xc020d8e348 pc=0x10d0e11
strings.genSplit(0xc000020dc0, 0x1a, 0x1465e06, 0x1, 0x0, 0xffffffffffffffff, 0x0, 0x0, 0x0)
/usr/local/Cellar/go/1.11.5/libexec/src/strings/strings.go:248 +0x248 fp=0xc020d8e3b0 sp=0xc020d8e350 pc=0x10d18d8
strings.Split(0xc000020dc0, 0x1a, 0x1465e06, 0x1, 0x0, 0x0, 0x0)
/usr/local/Cellar/go/1.11.5/libexec/src/strings/strings.go:303 +0x5b fp=0xc020d8e408 sp=0xc020d8e3b0 pc=0x10d1a8b
github.com/deepmap/oapi-codegen/pkg/codegen.RefPathToGoType(0xc000020dc0, 0x1a, 0x0, 0x0, 0x0, 0x0)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/utils.go:198 +0x4e fp=0xc020d8e450 sp=0xc020d8e408 pc=0x139075e
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b63, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:92 +0x18ae fp=0xc020d8ebb0 sp=0xc020d8e450 pc=0x138a15e
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b63, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d8f310 sp=0xc020d8ebb0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b62, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d8fa70 sp=0xc020d8f310 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b62, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d901d0 sp=0xc020d8fa70 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b61, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d90930 sp=0xc020d901d0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b61, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d91090 sp=0xc020d90930 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b60, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d917f0 sp=0xc020d91090 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b60, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d91f50 sp=0xc020d917f0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b5f, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d926b0 sp=0xc020d91f50 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b5f, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d92e10 sp=0xc020d926b0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b5e, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d93570 sp=0xc020d92e10 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b5e, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d93cd0 sp=0xc020d93570 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b5d, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d94430 sp=0xc020d93cd0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b5d, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d94b90 sp=0xc020d94430 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b5c, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d952f0 sp=0xc020d94b90 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b5c, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d95a50 sp=0xc020d952f0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b5b, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d961b0 sp=0xc020d95a50 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b5b, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d96910 sp=0xc020d961b0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b5a, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d97070 sp=0xc020d96910 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b5a, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d977d0 sp=0xc020d97070 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b59, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d97f30 sp=0xc020d977d0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b59, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d98690 sp=0xc020d97f30 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b58, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d98df0 sp=0xc020d98690 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b58, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d99550 sp=0xc020d98df0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b57, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d99cb0 sp=0xc020d99550 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b57, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d9a410 sp=0xc020d99cb0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b56, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d9ab70 sp=0xc020d9a410 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b56, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d9b2d0 sp=0xc020d9ab70 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b55, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d9ba30 sp=0xc020d9b2d0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b55, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d9c190 sp=0xc020d9ba30 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b54, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d9c8f0 sp=0xc020d9c190 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b54, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d9d050 sp=0xc020d9c8f0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b53, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d9d7b0 sp=0xc020d9d050 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b53, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d9df10 sp=0xc020d9d7b0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b52, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d9e670 sp=0xc020d9df10 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b52, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d9edd0 sp=0xc020d9e670 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b51, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020d9f530 sp=0xc020d9edd0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b51, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020d9fc90 sp=0xc020d9f530 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b50, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da03f0 sp=0xc020d9fc90 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b50, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da0b50 sp=0xc020da03f0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b4f, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da12b0 sp=0xc020da0b50 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b4f, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da1a10 sp=0xc020da12b0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b4e, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da2170 sp=0xc020da1a10 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b4e, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da28d0 sp=0xc020da2170 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b4d, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da3030 sp=0xc020da28d0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b4d, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da3790 sp=0xc020da3030 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b4c, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da3ef0 sp=0xc020da3790 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b4c, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da4650 sp=0xc020da3ef0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b4b, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da4db0 sp=0xc020da4650 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b4b, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da5510 sp=0xc020da4db0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b4a, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da5c70 sp=0xc020da5510 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b4a, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da63d0 sp=0xc020da5c70 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b49, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da6b30 sp=0xc020da63d0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b49, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da7290 sp=0xc020da6b30 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b48, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da79f0 sp=0xc020da7290 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b48, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da8150 sp=0xc020da79f0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b47, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da88b0 sp=0xc020da8150 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b47, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da9010 sp=0xc020da88b0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b46, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020da9770 sp=0xc020da9010 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b46, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020da9ed0 sp=0xc020da9770 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b45, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020daa630 sp=0xc020da9ed0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b45, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020daad90 sp=0xc020daa630 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b44, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020dab4f0 sp=0xc020daad90 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b44, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020dabc50 sp=0xc020dab4f0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b43, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020dac3b0 sp=0xc020dabc50 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b43, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020dacb10 sp=0xc020dac3b0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b42, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020dad270 sp=0xc020dacb10 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b42, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020dad9d0 sp=0xc020dad270 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b41, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020dae130 sp=0xc020dad9d0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b41, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020dae890 sp=0xc020dae130 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b40, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020daeff0 sp=0xc020dae890 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b40, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020daf750 sp=0xc020daeff0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b3f, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020dafeb0 sp=0xc020daf750 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b3f, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db0610 sp=0xc020dafeb0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b3e, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db0d70 sp=0xc020db0610 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b3e, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db14d0 sp=0xc020db0d70 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b3d, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db1c30 sp=0xc020db14d0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b3d, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db2390 sp=0xc020db1c30 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b3c, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db2af0 sp=0xc020db2390 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b3c, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db3250 sp=0xc020db2af0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b3b, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db39b0 sp=0xc020db3250 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b3b, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db4110 sp=0xc020db39b0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b3a, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db4870 sp=0xc020db4110 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b3a, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db4fd0 sp=0xc020db4870 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b39, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db5730 sp=0xc020db4fd0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b39, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db5e90 sp=0xc020db5730 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b38, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db65f0 sp=0xc020db5e90 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b38, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db6d50 sp=0xc020db65f0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b37, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db74b0 sp=0xc020db6d50 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b37, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db7c10 sp=0xc020db74b0 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b36, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db8370 sp=0xc020db7c10 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b36, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db8ad0 sp=0xc020db8370 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b35, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020db9230 sp=0xc020db8ad0 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b35, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020db9990 sp=0xc020db9230 pc=0x1389840
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00000de80, 0xc04157a000, 0x22b34, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:149 +0x274 fp=0xc020dba0f0 sp=0xc020db9990 pc=0x1388b24
github.com/deepmap/oapi-codegen/pkg/codegen.GenerateGoSchema(0xc00015c220, 0xc04157a000, 0x22b34, 0x24400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/duncan/go/src/github.com/deepmap/oapi-codegen/pkg/codegen/schema.go:203 +0xf90 fp=0xc020dba850 sp=0xc020dba0f0 pc=0x1389840
...additional frames elided...

</details>

chi-server generated API sets content type of text/plain

  1. Problem

When I generate the server code for chi, the response is always of type text/plain. Even setting

import "github.com/go-chi/render"

r := chi.NewRouter()
r.Use(render.SetContentType(render.ContentTypeJSON))

produces content-type text/pain.

  1. Expected
    Either response is of content-type application/json or respects set headers

Why are response models private?

I want to use API response models from other packages, but for some reason they are now generated privately (their names begin with a small letter):

type getFirstPetResponse struct {
	Body         []byte
	HTTPResponse *http.Response
	JSON200      *Pet
}

Why are they private?

Multiple url params - context error

When using nested URLs of entities like /pets/petID/dogs/dogID

The generator create the following code (middleware):

ctx := context.WithValue(r, "petID", 1)
ctx = context.WithValue(r, "dogID", 2)

Instead

ctx := context.WithValue(r, "petID", 1)
ctx = context.WithValue(ctx, "dogID", 2)

Because of what the variable petID is not available in handler

Support "date" string format during marshaling

Version: 1.3.0

I have noticed that if I have a spec that includes a date field:

birthday:
  type: string
  format: date

My generated clients will have a *time.Time field created in the parameters struct. This works fine during unmarshaling, but a marshaled time.Time will not be in the date format 2017-07-21, but the datetime format 2017-07-21T00:00:00Z. This may throw off servers with strict input validation.

golint compliance

The generated code and the code of the project itself causes a lot of warnings in the GoLand IDE and when checking with golint.

How about bringing code into line with golint?

I could help with that.

golint ./...
examples/petstore-expanded/chi/petstore_test.go:16:6: func DoJson should be DoJSON
examples/petstore-expanded/chi/api/petstore.go:12:6: exported type PetStore should have comment or be unexported
examples/petstore-expanded/chi/api/petstore.go:14:2: struct field NextId should be NextID
examples/petstore-expanded/chi/api/petstore.go:18:1: exported function NewPetStore should have comment or be unexported
examples/petstore-expanded/chi/api/petstore.go:36:1: comment on exported method PetStore.FindPets should be of the form "FindPets ..."
examples/petstore-expanded/chi/api/petstore.go:71:1: exported method PetStore.AddPet should have comment or be unexported
examples/petstore-expanded/chi/api/petstore.go:100:1: exported method PetStore.FindPetById should have comment or be unexported
examples/petstore-expanded/chi/api/petstore.go:100:20: method FindPetById should be FindPetByID
examples/petstore-expanded/chi/api/petstore.go:116:1: exported method PetStore.DeletePet should have comment or be unexported
examples/petstore-expanded/echo/petstore_test.go:80:2: var petId should be petID
examples/petstore-expanded/echo/petstore_test.go:110:2: var petId2 should be petID2
examples/petstore-expanded/echo/api/petstore.go:28:6: exported type PetStore should have comment or be unexported
examples/petstore-expanded/echo/api/petstore.go:30:2: struct field NextId should be NextID
examples/petstore-expanded/echo/api/petstore.go:34:1: exported function NewPetStore should have comment or be unexported
examples/petstore-expanded/echo/api/petstore.go:52:1: comment on exported method PetStore.FindPets should be of the form "FindPets ..."
examples/petstore-expanded/echo/api/petstore.go:83:1: exported method PetStore.AddPet should have comment or be unexported
examples/petstore-expanded/echo/api/petstore.go:122:1: exported method PetStore.FindPetById should have comment or be unexported
examples/petstore-expanded/echo/api/petstore.go:122:20: method FindPetById should be FindPetByID
examples/petstore-expanded/echo/api/petstore.go:122:50: method parameter petId should be petID
examples/petstore-expanded/echo/api/petstore.go:134:1: exported method PetStore.DeletePet should have comment or be unexported
examples/petstore-expanded/internal/doc.go:1:1: package comment should be of the form "Package internal ..."
internal/test/components/components_test.go:10:6: func assertJsonEqual should be assertJSONEqual
internal/test/issues/issue-52/doc.go:1:1: don't use an underscore in package name
internal/test/issues/issue-52/issue_test.go:1:1: don't use an underscore in package name
pkg/codegen/codegen.go:242:1: exported function GenerateTypeDefinitions should have comment or be unexported
pkg/codegen/codegen.go:285:1: comment on exported function GenerateTypesForSchemas should be of the form "GenerateTypesForSchemas ..."
pkg/codegen/codegen.go:309:1: comment on exported function GenerateTypesForParameters should be of the form "GenerateTypesForParameters ..."
pkg/codegen/codegen.go:341:1: comment on exported function GenerateTypesForResponses should be of the form "GenerateTypesForResponses ..."
pkg/codegen/codegen.go:380:1: comment on exported function GenerateTypesForRequestBodies should be of the form "GenerateTypesForRequestBodies ..."
pkg/codegen/codegen.go:418:1: comment on exported function GenerateTypes should be of the form "GenerateTypes ..."
pkg/codegen/codegen.go:441:1: comment on exported function GenerateImports should be of the form "GenerateImports ..."
pkg/codegen/codegen.go:465:1: comment on exported function GenerateAdditionalPropertyBoilerplate should be of the form "GenerateAdditionalPropertyBoilerplate ..."
pkg/codegen/inline.go:1:1: package comment should be of the form "Package codegen ..."
pkg/codegen/inline.go:27:1: comment on exported function GenerateInlinedSpec should be of the form "GenerateInlinedSpec ..."
pkg/codegen/operations.go:1:1: package comment should be of the form "Package codegen ..."
pkg/codegen/operations.go:28:6: exported type ParameterDefinition should have comment or be unexported
pkg/codegen/operations.go:36:1: comment on exported method ParameterDefinition.TypeDef should be of the form "TypeDef ..."
pkg/codegen/operations.go:44:1: comment on exported method ParameterDefinition.JsonTag should be of the form "JsonTag ..."
pkg/codegen/operations.go:47:32: method JsonTag should be JSONTag
pkg/codegen/operations.go:50:9: if block ends with a return statement, so drop this else and outdent its block
pkg/codegen/operations.go:55:1: exported method ParameterDefinition.IsJson should have comment or be unexported
pkg/codegen/operations.go:55:32: method IsJson should be IsJSON
pkg/codegen/operations.go:64:1: exported method ParameterDefinition.IsPassThrough should have comment or be unexported
pkg/codegen/operations.go:75:1: exported method ParameterDefinition.IsStyled should have comment or be unexported
pkg/codegen/operations.go:80:1: exported method ParameterDefinition.Style should have comment or be unexported
pkg/codegen/operations.go:96:1: exported method ParameterDefinition.Explode should have comment or be unexported
pkg/codegen/operations.go:111:1: exported method ParameterDefinition.GoVariableName should have comment or be unexported
pkg/codegen/operations.go:122:1: exported method ParameterDefinition.GoName should have comment or be unexported
pkg/codegen/operations.go:126:1: exported method ParameterDefinition.IndirectOptional should have comment or be unexported
pkg/codegen/operations.go:130:6: exported type ParameterDefinitions should have comment or be unexported
pkg/codegen/operations.go:132:1: exported method ParameterDefinitions.FindByName should have comment or be unexported
pkg/codegen/operations.go:141:1: comment on exported function DescribeParameters should be of the form "DescribeParameters ..."
pkg/codegen/operations.go:179:6: exported type SecurityDefinition should have comment or be unexported
pkg/codegen/operations.go:184:1: exported function DescribeSecurityDefinition should have comment or be unexported
pkg/codegen/operations.go:196:1: comment on exported type OperationDefinition should be of the form "OperationDefinition ..." (with optional leading article)
pkg/codegen/operations.go:198:2: struct field OperationId should be OperationID
pkg/codegen/operations.go:214:1: comment on exported method OperationDefinition.Params should be of the form "Params ..."
pkg/codegen/operations.go:222:1: comment on exported method OperationDefinition.AllParams should be of the form "AllParams ..."
pkg/codegen/operations.go:230:1: comment on exported method OperationDefinition.RequiresParamObject should be of the form "RequiresParamObject ..."
pkg/codegen/operations.go:237:1: comment on exported method OperationDefinition.HasBody should be of the form "HasBody ..."
pkg/codegen/operations.go:244:1: comment on exported method OperationDefinition.SummaryAsComment should be of the form "SummaryAsComment ..."
pkg/codegen/operations.go:257:1: comment on exported method OperationDefinition.GetResponseTypeDefinitions should be of the form "GetResponseTypeDefinitions ..."
pkg/codegen/operations.go:315:1: comment on exported type RequestBodyDefinition should be of the form "RequestBodyDefinition ..." (with optional leading article)
pkg/codegen/operations.go:335:1: comment on exported method RequestBodyDefinition.TypeDef should be of the form "TypeDef ..."
pkg/codegen/operations.go:340:1: comment on exported method RequestBodyDefinition.CustomType should be of the form "CustomType ..."
pkg/codegen/operations.go:347:1: comment on exported method RequestBodyDefinition.Suffix should be of the form "Suffix ..."
pkg/codegen/operations.go:358:1: comment on exported function FilterParameterDefinitionByType should be of the form "FilterParameterDefinitionByType ..."
pkg/codegen/operations.go:451:1: comment on exported function GenerateBodyDefinitions should be of the form "GenerateBodyDefinitions ..."
pkg/codegen/operations.go:515:1: exported function GenerateTypeDefsForOperation should have comment or be unexported
pkg/codegen/operations.go:533:1: comment on exported function GenerateParamsTypes should be of the form "GenerateParamsTypes ..."
pkg/codegen/operations.go:572:1: comment on exported function GenerateTypesForOperations should be of the form "GenerateTypesForOperations ..."
pkg/codegen/operations.go:665:1: comment on exported function GenerateServerInterface should be of the form "GenerateServerInterface ..."
pkg/codegen/operations.go:682:1: comment on exported function GenerateWrappers should be of the form "GenerateWrappers ..."
pkg/codegen/operations.go:701:1: comment on exported function GenerateRegistration should be of the form "GenerateRegistration ..."
pkg/codegen/operations.go:719:1: comment on exported function GenerateClient should be of the form "GenerateClient ..."
pkg/codegen/operations.go:737:1: comment on exported function GenerateClientWithResponses should be of the form "GenerateClientWithResponses ..."
pkg/codegen/schema.go:11:1: comment on exported type Schema should be of the form "Schema ..." (with optional leading article)
pkg/codegen/schema.go:24:1: exported method Schema.IsRef should have comment or be unexported
pkg/codegen/schema.go:28:1: exported method Schema.TypeDecl should have comment or be unexported
pkg/codegen/schema.go:35:1: exported method Schema.MergeProperty should have comment or be unexported
pkg/codegen/schema.go:46:1: exported method Schema.GetAdditionalTypeDefs should have comment or be unexported
pkg/codegen/schema.go:55:6: exported type Property should have comment or be unexported
pkg/codegen/schema.go:56:2: struct field JsonFieldName should be JSONFieldName
pkg/codegen/schema.go:61:1: exported method Property.GoFieldName should have comment or be unexported
pkg/codegen/schema.go:65:1: exported method Property.GoTypeDef should have comment or be unexported
pkg/codegen/schema.go:73:6: exported type TypeDefinition should have comment or be unexported
pkg/codegen/schema.go:75:2: struct field JsonName should be JSONName
pkg/codegen/schema.go:80:1: exported function PropertiesEqual should have comment or be unexported
pkg/codegen/schema.go:84:1: exported function GenerateGoSchema should have comment or be unexported
pkg/codegen/schema.go:200:9: if block ends with a return statement, so drop this else and outdent its block
pkg/codegen/schema.go:256:1: comment on exported type SchemaDescriptor should be of the form "SchemaDescriptor ..." (with optional leading article)
pkg/codegen/schema.go:263:6: exported type FieldDescriptor should have comment or be unexported
pkg/codegen/schema.go:267:2: struct field JsonName should be JSONName
pkg/codegen/schema.go:271:1: comment on exported function GenFieldsFromProperties should be of the form "GenFieldsFromProperties ..."
pkg/codegen/schema.go:287:1: exported function GenStructFromSchema should have comment or be unexported
pkg/codegen/schema.go:306:1: comment on exported function MergeSchemas should be of the form "MergeSchemas ..."
pkg/codegen/schema.go:359:1: comment on exported function GenStructFromAllOf should be of the form "GenStructFromAllOf ..."
pkg/codegen/template_helpers.go:1:1: package comment should be of the form "Package codegen ..."
pkg/codegen/template_helpers.go:222:1: comment on exported var TemplateFunctions should be of the form "TemplateFunctions ..."
pkg/codegen/utils.go:1:1: package comment should be of the form "Package codegen ..."
pkg/codegen/utils.go:42:1: comment on exported function UppercaseFirstCharacter should be of the form "UppercaseFirstCharacter ..."
pkg/codegen/utils.go:53:1: comment on exported function LowercaseFirstCharacter should be of the form "LowercaseFirstCharacter ..."
pkg/codegen/utils.go:63:1: comment on exported function ToCamelCase1 should be of the form "ToCamelCase1 ..."
pkg/codegen/utils.go:89:1: comment on exported function ToCamelCase should be of the form "ToCamelCase ..."
pkg/codegen/utils.go:104:1: comment on exported function SortedSchemaKeys should be of the form "SortedSchemaKeys ..."
pkg/codegen/utils.go:117:1: comment on exported function SortedPathsKeys should be of the form "SortedPathsKeys ..."
pkg/codegen/utils.go:130:1: comment on exported function SortedOperationsKeys should be of the form "SortedOperationsKeys ..."
pkg/codegen/utils.go:142:1: comment on exported function SortedResponsesKeys should be of the form "SortedResponsesKeys ..."
pkg/codegen/utils.go:154:1: comment on exported function SortedContentKeys should be of the form "SortedContentKeys ..."
pkg/codegen/utils.go:166:1: comment on exported function SortedStringKeys should be of the form "SortedStringKeys ..."
pkg/codegen/utils.go:178:1: comment on exported function SortedParameterKeys should be of the form "SortedParameterKeys ..."
pkg/codegen/utils.go:190:1: exported function SortedRequestBodyKeys should have comment or be unexported
pkg/codegen/utils.go:201:1: comment on exported function StringInArray should be of the form "StringInArray ..."
pkg/codegen/utils.go:212:1: comment on exported function RefPathToGoType should be of the form "RefPathToGoType ..."
pkg/codegen/utils.go:232:1: comment on exported function SwaggerUriToEchoUri should be of the form "SwaggerUriToEchoUri ..."
pkg/codegen/utils.go:243:6: func SwaggerUriToEchoUri should be SwaggerURIToEchoURI
pkg/codegen/utils.go:247:1: comment on exported function SwaggerUriToChiUri should be of the form "SwaggerUriToChiUri ..."
pkg/codegen/utils.go:258:6: func SwaggerUriToChiUri should be SwaggerURIToChiURI
pkg/codegen/utils.go:262:1: comment on exported function OrderedParamsFromUri should be of the form "OrderedParamsFromUri ..."
pkg/codegen/utils.go:264:6: func OrderedParamsFromUri should be OrderedParamsFromURI
pkg/codegen/utils.go:273:1: comment on exported function ReplacePathParamsWithStr should be of the form "ReplacePathParamsWithStr ..."
pkg/codegen/utils.go:278:1: comment on exported function SortParamsByPath should be of the form "SortParamsByPath ..."
pkg/codegen/utils.go:298:1: comment on exported function IsGoKeyword should be of the form "IsGoKeyword ..."
pkg/codegen/utils.go:336:1: comment on exported function SchemaNameToTypeName should be of the form "SchemaNameToTypeName ..."
pkg/codegen/utils.go:347:1: comment on exported function SchemaHasAdditionalProperties should be of the form "SchemaHasAdditionalProperties ..."
pkg/codegen/utils.go:363:1: comment on exported function PathToTypeName should be of the form "PathToTypeName ..."
pkg/middleware/oapi_validate.go:29:7: exported const EchoContextKey should have comment or be unexported
pkg/middleware/oapi_validate.go:30:7: exported const UserDataKey should have comment or be unexported
pkg/middleware/oapi_validate.go:36:1: comment on exported function OapiValidatorFromYamlFile should be of the form "OapiValidatorFromYamlFile ..."
pkg/middleware/oapi_validate.go:51:1: comment on exported function OapiRequestValidator should be of the form "OapiRequestValidator ..."
pkg/middleware/oapi_validate.go:64:1: comment on exported function OapiRequestValidatorWithOptions should be of the form "OapiRequestValidatorWithOptions ..."
pkg/middleware/oapi_validate.go:78:1: comment on exported function ValidateRequestFromContext should be of the form "ValidateRequestFromContext ..."
pkg/middleware/oapi_validate.go:107:20: should not use basic type string as key in context.WithValue
pkg/middleware/oapi_validate.go:112:20: should not use basic type string as key in context.WithValue
pkg/middleware/oapi_validate.go:136:1: comment on exported function GetEchoContext should be of the form "GetEchoContext ..."
pkg/middleware/oapi_validate.go:150:1: exported function GetUserData should have comment or be unexported
pkg/runtime/bindparam.go:1:1: package comment should be of the form "Package runtime ..."
pkg/runtime/bindparam.go:27:1: comment on exported function BindStyledParameter should be of the form "BindStyledParameter ..."
pkg/runtime/bindparam.go:105:10: if block ends with a return statement, so drop this else and outdent its block
pkg/runtime/bindparam.go:134:10: if block ends with a return statement, so drop this else and outdent its block
pkg/runtime/bindparam.go:154:10: if block ends with a return statement, so drop this else and outdent its block
pkg/runtime/bindparam.go:234:1: comment on exported function BindQueryParameter should be of the form "BindQueryParameter ..."
pkg/runtime/bindparam.go:310:13: if block ends with a return statement, so drop this else and outdent its block
pkg/runtime/bindparam.go:328:13: if block ends with a return statement, so drop this else and outdent its block
pkg/runtime/bindparam.go:347:10: if block ends with a return statement, so drop this else and outdent its block
pkg/runtime/bindparam.go:353:12: if block ends with a return statement, so drop this else and outdent its block
pkg/runtime/bindparam.go:374:12: if block ends with a return statement, so drop this else and outdent its block
pkg/runtime/bindstring.go:1:1: package comment should be of the form "Package runtime ..."
pkg/runtime/bindstring.go:24:1: comment on exported function BindStringToObject should be of the form "BindStringToObject ..."
pkg/runtime/router.go:1:1: package comment should be of the form "Package runtime ..."
pkg/runtime/router.go:20:1: comment on exported type EchoRouter should be of the form "EchoRouter ..." (with optional leading article)
pkg/runtime/styleparam.go:1:1: package comment should be of the form "Package runtime ..."
pkg/runtime/styleparam.go:25:1: comment on exported function StyleParam should be of the form "StyleParam ..."
pkg/testutil/request_helpers.go:1:1: package comment should be of the form "Package testutil ..."
pkg/testutil/request_helpers.go:39:1: exported function NewRequest should have comment or be unexported
pkg/testutil/request_helpers.go:45:1: comment on exported type RequestBuilder should be of the form "RequestBuilder ..." (with optional leading article)
pkg/testutil/request_helpers.go:55:1: comment on exported method RequestBuilder.WithMethod should be of the form "WithMethod ..."
pkg/testutil/request_helpers.go:62:1: exported method RequestBuilder.Get should have comment or be unexported
pkg/testutil/request_helpers.go:66:1: exported method RequestBuilder.Post should have comment or be unexported
pkg/testutil/request_helpers.go:70:1: exported method RequestBuilder.Put should have comment or be unexported
pkg/testutil/request_helpers.go:74:1: exported method RequestBuilder.Delete should have comment or be unexported
pkg/testutil/request_helpers.go:78:1: comment on exported method RequestBuilder.WithHeader should be of the form "WithHeader ..."
pkg/testutil/request_helpers.go:84:1: exported method RequestBuilder.WithContentType should have comment or be unexported
pkg/testutil/request_helpers.go:88:1: exported method RequestBuilder.WithJsonContentType should have comment or be unexported
pkg/testutil/request_helpers.go:88:26: method WithJsonContentType should be WithJSONContentType
pkg/testutil/request_helpers.go:92:1: exported method RequestBuilder.WithAccept should have comment or be unexported
pkg/testutil/request_helpers.go:96:1: exported method RequestBuilder.WithAcceptJson should have comment or be unexported
pkg/testutil/request_helpers.go:96:26: method WithAcceptJson should be WithAcceptJSON
pkg/testutil/request_helpers.go:102:1: exported method RequestBuilder.WithBody should have comment or be unexported
pkg/testutil/request_helpers.go:107:1: comment on exported method RequestBuilder.WithJsonBody should be of the form "WithJsonBody ..."
pkg/testutil/request_helpers.go:109:26: method WithJsonBody should be WithJSONBody
pkg/testutil/request_helpers.go:118:1: comment on exported method RequestBuilder.WithCookie should be of the form "WithCookie ..."
pkg/testutil/request_helpers.go:124:1: exported method RequestBuilder.WithCookieNameValue should have comment or be unexported
pkg/testutil/request_helpers.go:128:1: comment on exported method RequestBuilder.Go should be of the form "Go ..."
pkg/testutil/request_helpers.go:157:1: comment on exported type CompletedRequest should be of the form "CompletedRequest ..." (with optional leading article)
pkg/testutil/request_helpers.go:163:1: comment on exported method CompletedRequest.UnmarshalBodyToObject should be of the form "UnmarshalBodyToObject ..."
pkg/testutil/request_helpers.go:179:1: comment on exported method CompletedRequest.UnmarshalJsonToObject should be of the form "UnmarshalJsonToObject ..."
pkg/testutil/request_helpers.go:181:28: method UnmarshalJsonToObject should be UnmarshalJSONToObject
pkg/testutil/request_helpers.go:185:1: comment on exported method CompletedRequest.Code should be of the form "Code ..."

Clean up double-slashes in URLs

Version: 1.3.0

If I have a document that defines absolute path URLs like /api/pets and then use the WithBaseURL option with my generated client, like so:

_, _ = lib.NewClient(context.TODO(), lib.WithBaseURL("http://localhost"))

The URLs that will be hit for my client requests will contain a double-slash, like http://localhost//api/pets. Not the end of the world, but some servers may fail to understand this request.

Support wrapped http Clients using a HTTP client interface instead of the concrete http.Client

The standard library doesn't support features like Retry of error and different backoff strategies for the same. The recommended approach is to wrap the standard library HTTP client package with any custom handling logic. (See ianlancetaylor's reponse in golang/go#16047)
I propose adding an HTTPClient interface with the same method signatures as the standard library HTTP Client

    type Client
        func (c *Client) CloseIdleConnections()
        func (c *Client) Do(req *Request) (*Response, error)
        func (c *Client) Get(url string) (resp *Response, err error)
        func (c *Client) Head(url string) (resp *Response, err error)
        func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response, err error)
        func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error)

Added a PR for the same #86

Please let me know if this makes sense and can be supported. Would really benefit our team in adding retry mechanism to the client for all requests.

Flag for generating client or server only

I have an interest in just generating the HTTP client from swagger, although, I like the current behavior that generates both.

Is there any interest in a PR that would be something like --client-only or --server-only ?

Fallback to `interface{}` in case a type cannot be determined

In some weird OpenAPI specs, it is possible that you might have an array defined, but no items.
In the current implementation of oapi-codegen, this leads to a nullpointer-exception (NPE).

It would be better, if we could just fallback to an interface type. This way the generated Go-Code is fine and will compile, and it will be up to the user of the generated Go-Library to cast/map the interface{} to the appropiate Go-struct. It should not be a concern that the openapi-spec is crap, as long as we have interface{} available as a placeholder.

Add Go 1.13 reference in go.mod

Go 1.13 is out with language changes. It would be good to have it in go mod

See: https://golang.org/doc/go1.13#language

If your code uses modules and your go.mod files specifies a language version, be sure it is set to at least 1.13 to get access to these language changes. You can do this by editing the go.mod file directly, or you can run go mod edit -go=1.13.

Case mismatch between spec and generated wrappers

Hi,

I found another minor problem when you have capitalized header key, such as X-API-KEY: FooBar, Echo will convert it in a Header map with X-Api-Key key while the generated still looking for X-API-KEY.

There is 2 possible solution, using headers[strings.ToLower(strings.Title(strings.ToLower("X-API-KEY")) or headers.Get("X-API-KEY") however the latter solution probably going to change to template a lot because now it's return the first value they found.

Thanks!

Bug: Cannot distinguish between SecurityDefinitions override per path vs. inheriting global SecurityDefinitions

Bug

Type OperationDefinition assumes a slice SecurityDefinitions []SecurityDefinition as part of the operations, which are defined on a path.

See:
https://github.com/deepmap/oapi-codegen/blob/master/pkg/codegen/operations.go#L205

Explanation

This is problematic according to the Specification: https://swagger.io/docs/specification/authentication/

...
Step 2. Applying security
After you have defined the security schemes in the securitySchemes section, you can apply them to the whole API or individual operations by adding the security section on the root level or operation level, respectively. When used on the root level, security applies the specified security schemes globally to all API operations, unless overridden on the operation level. In the following example, the API calls can be authenticated using either an API key or OAuth 2. The ApiKeyAuth and OAuth2 names refer to the schemes previously defined in securitySchemes.

How to fix

Therfore to distinguish, whether a path wants to disable a globally defined securityScheme vs. inheriting the globally defined securityScheme, one has to use a pointer to a slice:

// use a pointer * to distinguish disable vs. inherit
`SecurityDefinitions *[]SecurityDefinition`

Missing Enum Values and validation code

I am trying to generate Golang code for following openapi 3 spec. I have doubts regarding Go code generation for enum related types.

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Swagger Petstore
  description: A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification
  termsOfService: http://swagger.io/terms/
  contact:
    name: Swagger API Team
    email: [email protected]
    url: http://swagger.io
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
  - url: http://petstore.swagger.io/api
paths:
  /pets:
    post:
      summary: Post a PetType Information.
      description: Post a PetType Information.
      operationId: postPets
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/Cat'
                - $ref: '#/components/schemas/Dog'
      responses:
        '200':
          description: Updated
    get:
      summary: Returns a pet info by given petType.
      description: Get Pet Infrmation based on pet type.
      operationId: getPets
      parameters:
        - $ref: '#/components/parameters/PetType'
        - in: query
          name: petColor
          schema:
            type: string
      responses:
        '200':
          description: Get Pet Type 
          content:
            application/json: 
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Cat'
                  - $ref: '#/components/schemas/Dog'
components:
  schemas:
    Pet:
      type: object
      properties:
        color:
          $ref: '#/components/schemas/Color'
        name:
          type: string
          nullable: true
        owners:
          type: array
          nullable: false
          items:
            type: object
            properties:
              ownerName:
                type: string
              ownerAddress:
                type: string
                nullable: true
    Dog:
      allOf:
        - $ref: '#/components/schemas/Pet'
        - type: object
          required:
            - bark
          properties:
            bark:
              type: boolean
            breed:  
              type: string
              enum: [Dingo, Husky, Retriever, Shepherd]
              nullable: true
    Cat:
      allOf:
        - $ref: '#/components/schemas/Pet'
        - type: object
          properties:
            hunts:
              type: boolean
              nullable: true
            age:
              type: number
              format: float
              nullable: true
    Color:
      type: string
      nullable: true
      enum: 
        - black
        - white
        - red
        - green
        - blue
    PetTypeEnum:
      type: string
      enum:
        - cat
        - dog
  parameters:
    PetType:
      name: petType
      in: query
      required: true
      schema:
        $ref: '#/components/schemas/PetTypeEnum'

In the generate go code, enums defined in the YAML such as 'Color' and 'PetTypeEnum' are generated as String type which is expected.

type Color string 

But there are no 'const' generated for possible set of enum values defined in the input spec. I was exepcting following code to be generated with above code.

const (
        BLACK Color = "black"
        WHITE Color = "white"
        RED Color = "red"
        GREEN Color = "green"
        BLUE Color = "blue"
) 

Is this behaviour by design? I also do not see any validation function which will validate the input value against the possible enum values for a given field.

Embed runtime code into generated boilerplate

We currently have generic handlers for parameters in the runtime package. These use either reflection or the swagger spec to generically handle any parameter.

A much better, though more difficult approach would be to generate the specific code to marshal and unmarshal each parameter from a query. We know the exact style, format and content for each parameter at generation time, so we only need a subset of the generic code to handle each, and that could be embedded without any conditional type logic where it's used.

The thought of the template code to do this, though, makes me shake with fear.

Discrepancies between go get binary and local build

Hey, initially I wanted to create an unrelated issue and submimt a PR for this, but I stumpled upon a strange problem that's hard for me to figure out. I hope someone here could help.

I have created a simple openapi spec file:

openapi: 3.0.2
info:
  version: '0.0.1'
  title: example
  desscription: |
    additionalProperties problem example

components:
  schemas:
    Translations:
      type: object
      additionalProperties:
        type: string

When I am using the openapi binary from the go/bin path, sourced like this:
go get -u github.com/deepmap/oapi-codegen/cmd/oapi-codegen from outside of my $GOPATH, the file generated (~/go/bin/oapi-codegen -generate types -o go.get.binary.go -package types spec.yml) looks like this:

// Package types provides primitives to interact the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT.
package types

// Translations defines model for Translations.
type Translations map[string]interface{}

When I am using the locally built binary:

cd cmd/oapi-codegen/ && GO111MODULE=on go build && cd - 
./cmd/oapi-codegen/oapi-codegen -generate types -o local.binary.go -package types spec.yml

it looks like this:

// Package types provides primitives to interact the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT.
package types

import (
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
)

// Translations defines model for Translations.
type Translations struct {
	AdditionalProperties map[string]string `json:"-"`
}

plus some additional methods.
Could someone please explain to me what I am doing wrong with the locally built binary?

Adding support for external refs

Hey thanks for writing this library, I know it's still early days for this library but I was wondering if there were any plans to add support for external refs?

e.g.

`$ref: "../resource.yml/#components/schemas/Hello"`

I had a play around enabling SwaggerLoader.IsExternalRefsAllowed but ran into this

Only local document components are supported

Happy to contribute a patch but before doing so was wondering if there was any reason in particular for not supporting this feature.

Issue with RequestBody types in generated code

Currently experiencing an issue where the {operation}JSONRequestBody types are not being used within the generated client methods.

e.g.

// spec.yaml

paths:
  /:
    post:
      operationId: create
      requestBody:
        content:
          application/json:
            schema:
              type: array
              items:
                $ref: '#/components/schemas/Data'

The generated API has the following types

// api.gen.go

type Data struct {
   ...
}

type createJSONBody []Data

type CreateJSONRequestBody createJSONBody

But, the client methods mistakenly use the createJSONBody type when they should use the CreateJSONRequestBody type.

The following is generated, and causes the client to error with cannot refer to unexported name api.createJSONBody

// api.gen.go

Create(ctx context.Context, body createJSONBody) (*http.Response, error)

...

func (c *Client) Create(ctx context.Context, body createJSONBody) (*createResponse, error) {
   ...
}

In my testing, manually changing this to CreateJSONRequestBody resolves the issue

// api.gen.go

type ClientInterface interface {
   Create(ctx context.Context, body CreateJSONRequestBody) (*http.Response, error)
}

...

func (c *Client) Create(ctx context.Context, body CreateJSONRequestBody) (*createResponse, error) {
   ...
}

This affects both the Client and ClientWithResponses methods.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.