swagger

module
v1.0.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 24, 2018 License: Apache-2.0

README

swagger

swagger is go-swagger with custom templates.

In Stratoscale, we really like the idea of API-first services, and we also really like Go. We saw the go-swagger library, and thought that most of it can really help us. Generating code from swagger files is a big problem with a lot of corner cases, and go-swagger is doing great job.

The one thing that we felt missing, is customization of the server to run with our design principles:

  • Custom main function
  • Dependency injection
  • Limited scopes with unit testing.

Also:

  • Adding you functions to the generated configure_swagger_*.go seems to be a burden.
  • Lack of Interface that the service implement.
  • Complicated and custom http clients and runtime.

Luckily, the go-swagger project gives an option to customize the templates it is using to generate the code. We re-wrote some of go-swagger's templates, and now we have:

Server

The new restapi package exposes interfaces
  • Those interfaces can implemented by the developer and are the business logic of the service.
  • The implementation of those is extensible.
  • The implementation is separated from the generated code.
The restapi returns an http.Handler

The restapi.Handler (see example) function returns a standard http.Handler

  • Given objects that implements the business logic, we can create a simple http handler.
  • This handler is standard go http.Handler, so we can now use any other middleware, library, or framework that support it.
  • This handler is standard, so we understand it better.

Client

  • The new client package exposes interfaces, so functions in our code can receive those interfaces which can be mocked for testing.
  • The new client has a config that gets an *url.URL to customize the endpoint.
  • The new client has a config that gets an http.RoundTripper to customize client with libraries, middleware or frameworks that support the standard library's objects.

Usage:

Using the docker container, add the following alias to a ~/.bashrc or similar

alias swagger="docker run --rm -it -e GOPATH=${GOPATH}:/go -v ${HOME}:${HOME} -w $(pwd) -u $(id -u):$(id -g) stratoscale/swagger:v1.0.0"

Then, use the swagger command:

swagger version

Example Walk-Through

In the example package you'll find generated code and usage of the pet-store swagger file.

  • The restapi, models and client are auto-generated by the stratoscale/swagger docker file.
  • The internal package was manually added and contains the server's business logic.
  • The main.go file is the entrypoint and contains initializations and dependency injections of the project.

Server

restapi

This package is autogenerated and contains the server routing and parameters parsing.

The modified version contains restapi.PetAPI and restapi.StoreAPI which were auto generated.

// PetAPI
type PetAPI interface {
	PetCreate(ctx context.Context, params pet.PetCreateParams) middleware.Responder
	PetDelete(ctx context.Context, params pet.PetDeleteParams) middleware.Responder
	PetGet(ctx context.Context, params pet.PetGetParams) middleware.Responder
	PetList(ctx context.Context, params pet.PetListParams) middleware.Responder
	PetUpdate(ctx context.Context, params pet.PetUpdateParams) middleware.Responder
}

//go:generate mockery -name StoreAPI -inpkg

// StoreAPI
type StoreAPI interface {
	InventoryGet(ctx context.Context, params store.InventoryGetParams) middleware.Responder
	OrderCreate(ctx context.Context, params store.OrderCreateParams) middleware.Responder
	// OrderDelete is For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors
	OrderDelete(ctx context.Context, params store.OrderDeleteParams) middleware.Responder
	// OrderGet is For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions
	OrderGet(ctx context.Context, params store.OrderGetParams) middleware.Responder
}

Each function matches an operationId in the swagger file and they are grouped according to the operation tags.

There is also a restapi.Config:

// Config is configuration for Handler
type Config struct {
	PetAPI
	StoreAPI
	Logger func(string, ...interface{})
	// InnerMiddleware is for the handler executors. These do not apply to the swagger.json document.
	// The middleware executes after routing but before authentication, binding and validation
	InnerMiddleware func(http.Handler) http.Handler
	// AuthMiddleware is middleware for authenticating general requests
	AuthMiddleware func(ctx *middleware.Context, next http.Handler) http.Handler
}

This config is auto generated and contains all the declared interfaces above. It is used to initiate an http.Handler with the Handler function:

// Handler returns an http.Handler given the handler configuration
// It mounts all the business logic implementers in the right routing.
func Handler(c Config) (http.Handler, error) {
    ...

Let's look how we use this generated code to build our server.

internal

The internal package is not auto generated and contains the business logic of our server. We can see two structs that implements the restapi.PetAPI and restapi.StoreAPI interfaces, needed to make our server work.

When adding or removing functions from our REST API, we can just add or remove functions to those business logic units. We can also create new logical units when they are added to our REST API.

main.go

The main function is pretty straight forward. We initiate our business logic units. Then create a config for our rest API. We then create a standard http.Handler which we can update with middleware, test with httptest, or to use with other standard tools. The last piece is to run the handler with http.ListenAndServe or to use it with an http.Server - it is all very customizable.

func main() {
	// Initiate business logic implementers.
	// This is the main function, so here the implementers' dependencies can be
	// injected, such as database, parameters from environment variables, or different
	// clients for different APIs.
	p := internal.Pet{}
	s := internal.Store{}

	// Initiate the http handler, with the objects that are implementing the business logic.
	h, err := restapi.Handler(restapi.Config{
		PetAPI:   &p,
		StoreAPI: &s,
		Logger:   log.Printf,
	})
	if err != nil {
		log.Fatal(err)
	}

	// Run the standard http server
	log.Fatal(http.ListenAndServe(":8080", h))
}

Client

The client code is in the client package and is autogenerated.

To create a new client we use the client.Config struct:

type Config struct {
	// URL is the base URL of the upstream server
	URL *url.URL
	// Transport is an inner transport for the client
	Transport http.RoundTripper
}

This enables us to use custom server endpoint or custom client middleware. Easily, with the standard components, and with any library that accepts them.

The client is then generated with the New method: // New creates a new swagger petstore HTTP client. func New(c Config) *SwaggerPetstore { ...


This method returns an object that has two important fields:

```go
	Pet       *pet.Client
	Store     *store.Client

Thos fields are objects, which implements interfaces declared in the pet and store packages:

For example:

// API is the interface of the pet client
type API interface {
	// PetCreate adds a new pet to the store
	PetCreate(ctx context.Context, params *PetCreateParams) (*PetCreateCreated, error)
	// PetDelete deletes a pet
	PetDelete(ctx context.Context, params *PetDeleteParams) (*PetDeleteNoContent, error)
	// PetGet gets pet by it s ID
	PetGet(ctx context.Context, params *PetGetParams) (*PetGetOK, error)
	// PetList lists pets
	PetList(ctx context.Context, params *PetListParams) (*PetListOK, error)
	// PetUpdate updates an existing pet
	PetUpdate(ctx context.Context, params *PetUpdateParams) (*PetUpdateCreated, error)
}

They are very similar to the server interfaces, and can be used by consumers of those APIs (instead of using the actual client or the *Pet struct)

Directories

Path Synopsis
client/pet
Code generated by mockery v1.0.0
Code generated by mockery v1.0.0
client/store
Code generated by mockery v1.0.0
Code generated by mockery v1.0.0
restapi
Package restapi Swagger Petstore This is a simplifed version of the sample server Petstore server.
Package restapi Swagger Petstore This is a simplifed version of the sample server Petstore server.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL