Categorygithub.com/soldatov-s/go-swagger
module
1.2.0
Repository: https://github.com/soldatov-s/go-swagger.git
Documentation: pkg.go.dev

# README

PkgGoDev License

go-swagger

Create Swagger (OpenAPI 2.0) descriptions via code helpers.

Purposes

In ideal world always at first creates scheme and describe all contracts between client and backend. In real world more simply create project and after describe swagger scheme. And if you at first create schemes, after some iterations you could optimize generated code and lost combability with schemes. This framework works as wizard and help doesn't forgot some fields in swagger description.

Features

Generates swagger description (only JSON) at Runtime by using the reflect package. Supported generation swagger description for Echo/Gorilla routers is supported. A separate package is implemented for each router. The framework contains two main components:

  • a builder that collects and connects the swagger web interface to the specified endpoint;
  • descriptor for endpoint.

Bulder

Starts by calling function BuildSwagger. The function must be called after adding endpoint to routs. The following parameters are supported:

ParameterDescription
router/srv (Gorilla/Echo)router/server (Gorilla/Echo) for which builds swagger
swaggerPaththe swagger-endpoint name
addressaddress on which will be showed swagger-description
swswagger-structure for adding endpoint description

For correct writes swagger-structure used a sequence of interfaces:

swagger.NewSwagger().SetBasePath("/api/v1").SetInfo(...)
FunctionDescriptionExample
SetBasePathbase path to api/api/v1
SetInfoinformation about http-service swagger-

SetInfo function accepts structure which describes information about service. In current version no hard sequence for writing information (yes, it's bad, you can write something twice). The interface for writing SetInfo contains next functions:

FunctionDescriptionExample
SetTitlethe service nameSwagger Example API
SetDescriptionthe service descriptionThis is a sample embedded Swagger-server for Echo-server.
SetTermOfServiceURL to termshttp://swagger.io/terms/
SetContactcontacts-
SetLicenselicence-

SetContact function accepts structure which describes information about contacts. In current version no hard sequence for writing information (yes, it's bad, you can write something twice). The interface for writing SetContact contains next functions:

FunctionDescriptionExample
SetEmailset email[email protected]
SetNameset support nameAPI Support
SetURLset URLhttps://test.test

SetLicense function accepts structure which describes information about licence. In current version no hard sequence for writing information (yes, it's bad, you can write something twice). The interface for writing SetLicense contains next functions:

FunctionDescriptionExample
SetURLURL to licencehttp://www.apache.org/licenses/LICENSE-2.0.html
SetNameThe licence nameApache 2.0

Example (Echo)

func main() {
	// Create http-server
	srv := echo.New()

	// Adds routes
	v1 := srv.Group("/api/v1")
	v1.GET("/test", testGetHandler)
	v1.POST("/test", testPostHandler)
	v1.GET("/testWithoutSwagger", testWithoutSwaggerGetHandler)
	v1.GET("/testWithMiddleware", testWithMiddlewareGetHandler, Middleware)
	v1.GET("/testArray", testArrayGetHandler)
	v1.GET("/testArrayOfStruct", testArrayOfStructGetHandler)
	v1.GET("/testParamPath/:id/:name", testParamPathGetHandler)

	// Build swagger
	err := echoSwagger.BuildSwagger(
		srv,
		"/swagger/*",
		":1323",
		swagger.NewSwagger().
			SetBasePath("/api/v1/").
			SetInfo(swagger.NewInfo().
				SetTitle("Swagger Example API v1").
				SetDescription("This is a sample embedded Swagger-server for Echo-server.").
				SetTermOfService("http://swagger.io/terms/").
				SetContact(swagger.NewContact()).
				SetLicense(swagger.NewLicense())),
		nil,
	)

	if err != nil {
		return
	}

	srv.HideBanner = true
	srv.Logger.Fatal(srv.Start(":1323"))
}

Example (Gorilla)

func main() {
	r := mux.NewRouter()
	v1 := r.PathPrefix("/api/v1").Subrouter()
	v1.HandleFunc("/test", testGetHandler).Methods("GET")
	v1.HandleFunc("/test", testPostHandler).Methods("POST")
	v1.HandleFunc("/testWithoutSwagger", testWithoutSwaggerGetHandler).Methods("GET")
	v1.Handle("/testWithMiddleware", Middleware(http.HandlerFunc(testWithMiddlewareGetHandler))).Methods("GET")
	v1.HandleFunc("/testArray", testArrayGetHandler).Methods("GET")
	v1.HandleFunc("/testArrayOfStruct", testArrayOfStructGetHandler).Methods("GET")
	v1.HandleFunc("/testParamPath/{id}/{name}", testParamPathGetHandler).Methods("GET")

	// Build swagger
	err := gorillaSwagger.BuildSwagger(
		r,
		"/swagger/",
		":1323",
		swagger.NewSwagger().
			SetBasePath("/api/v1/").
			SetInfo(swagger.NewInfo().
				SetTitle("Swagger Example API v1").
				SetDescription("This is a sample embedded Swagger-server for Gorilla-server.").
				SetTermOfService("http://swagger.io/terms/").
				SetContact(swagger.NewContact()).
				SetLicense(swagger.NewLicense())),
		nil,
	)

	if err != nil {
		return
	}

	srv := &http.Server{
		Handler: r,
		Addr:    ":1323",
	}

	log.Fatal(srv.ListenAndServe())
}

Descriptor for endpoint

The descriptor is implemented as sequence interfaces, which maximally excludes incorrect endpoint descriptions. The descriptor is called by the AddToSwagger function. A router context object is passed to it. For Echo - echo.Context, for Gorilla - *http.Request. Function AddToSwagger retruns interface with next functions:

FunctionDescriptionExample
SetConsumesset consumed dataapplication/json
SetProducesset produced dataapplication/json
AddResponseadd responses from endpoint-

SetConsumes accepts array of strings with supported consumed data formats and returns interface with next functions:

FunctionDescriptionExample
SetDescriptionset endpoint descriptionTest PostHandler
SetProducesset produced formatapplication/json

SetProduces accepts array of strings with supported produced data formats and returns interface with next functions:

FunctionDescriptionExample
SetDescriptionset endpoint descriptionTest simply POST PostHandler

SetDescription returns interface with next functions:

FunctionDescriptionExample
SetSummaryset short description for endpointTest handler

SetSummary returns interface with next functions:

FunctionDescriptionExample
AddResponseadd response from endpoint-
AddInBodyParameteradd description of in-body parameter-
AddInPathParameteradd description of in-path parameter-
AddInQueryParameteradd description of in-query parameter-
AddInHeaderParameteradd description of in-header parameter-
AddInCookieParameteradd description of in-cookie parameter-
  • The function AddInBodyParameter intended to describe in body parameter. According to the swagger 2.0 specification, there can be only one for a specific endpoint.
  • The functions AddInPathParameter anf AddInQueryParameter intended to describe in path, in query, in header, in cookie parameters. According to the swagger 2.0 specification, there may be several of them. WARNING! Cookie not supported in Swagger UI, adds it only for generation scheme. Therefore the returned by AddInBodyParameter/AddInPathParameter/AddInQueryParameter functions interface contains only next functions:
FunctionDescriptionExample
AddResponseadd response from endpoint-
AddInPathParameteradd description of in-path parameter-
AddInQueryParameteradd description of in-query parameter-
AddInHeaderParameteradd description of in-header parameter-
AddInCookieParameteradd description of in-cookie parameter-

AddResponse returns interface which have only function AddResponse.

For processing descriptor only once use function IsBuildingSwagger.

AddInBodyParameter

Accepts the name of parameter, its description, scheme and the flag required or not parameter.

AddInPathParameter

Accepts the name of parameter, its description, type of parameter.

AddInQueryParameter

Accepts the name of parameter, its description, type of parameter and the flag required or not parameter.

AddInHeaderParameter

Accepts the name of parameter, its description, type of parameter and the flag required or not parameter.

AddResponse

Accepts response code, its description, scheme.

Examples of using descriptor for endpoint

Example (Gorilla)

	// Swagger
	if gorillaSwagger.IsBuildingSwagger(r) {
		gorillaSwagger.AddToSwagger(r).
			SetConsumes("application/json").
			SetProduces("application/json").
			SetDescription("Test PostHandler").
			SetSummary("Test simply POST handler").
			AddInBodyParameter("some_id", "Some ID", &TestStruct{}, true).
			AddResponse(200, "Test", &TestStructWithInterfaceField{InterfaceField: TestStruct{Name: "dsgsdgs"}}).
			AddResponse(402, "Test", &TestStructWithStructField{})
		return
	}

Example (Echo)

	// Swagger
	if echoSwagger.IsBuildingSwagger(ec) {
		echoSwagger.AddToSwagger(ec).
			SetConsumes("application/json").
			SetProduces("application/json").
			SetDescription("Test PostHandler").
			SetSummary("Test simply POST handler").
			AddInBodyParameter("some_id", "Some ID", &TestStruct{}, false).
			AddResponse(200, "Test", &TestStructWithInterfaceField{InterfaceField: TestStruct{Name: "dsgsdgs"}}).
			AddResponse(402, "Test", &TestStructWithStructField{})
		return nil
	}

Supported schemes

  • Nested structs:
type TestStruct struct {
	Name   string `json:"name"`
	Conter int    `json:"counter"`
}

type TestStructWithStructField struct {
	StructField TestStruct `json:"structField"`
}
  • Nested slices of structs:
type TestEeee struct {
	Name   string `json:"Name"`
	Conter int    `json:"conter"`
}

type TestStructWithArrayOfStructs struct {
	ArrayField []TestEeee `json:"arrayField"`
}
  • Nested slices of siple types.

  • Nested interfaces:

type TestStructWithInterfaceField struct {
	Str            string      `json:"str"`
	InterfaceField interface{} `json:"interfaceField"`
}

Supporting Middleware

go-swagger works with middlewares correctly. If Middleware is available, they will be processed correctly and will not be counted as a separate method at the endpoint. You can specify a swagger description for the Middleware response if there is a condition under which the request is not forwarded further to the endpoint

Example (Gorilla):

func Middleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Swagger
		if gorillaSwagger.IsBuildingSwagger(r) {
			gorillaSwagger.AddToSwagger(r).
				AddResponse(405, "Test middleware response", nil)
		}

		// Main code of handler
		if r.URL.Query().Get("some_id") == "fail" {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}
		next.ServeHTTP(w, r)
	})
}

Example (Echo):

func Middleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(ec echo.Context) error {
		// Swagger
		if echoSwagger.IsBuildingSwagger(ec) {
			echoSwagger.AddToSwagger(ec).
				AddResponse(405, "Test middleware response", nil)
		}

		// Main code of handler
		if ec.QueryParam("some_id") == "fail" {
			ec.Response().WriteHeader(http.StatusMethodNotAllowed)
			return nil
		}
		if err := next(ec); err != nil {
			ec.Error(err)
		}
		return nil
	}
}
  • Exclude endpoint from swagger-description Use middleware ExcludeFromSwagger for it. If no descriptor for endpoint this endpoint will not included to swagger-description, but you can see some errors in log when swagger-description will be build.

Multiple swagger-descriptions at one address

You can create multiple swagger-descriptions at one address. E.x. for "api/v1" for "api/2".

Types substitution

During generated swagger-description you can replace one type to another. For example, for save memory useful to use int instead string constants. But in contract will be string. If you do not make a substitution of the type, then the swagger description will contain an int, which is misleading. To avoid the "swagtype" tag, if it is present, the parser will replace the real type with capabilities.

type TestStructWithStructField struct {
  TestIntAsString  int                    `json:"testIntAsString" swagtype:"string"`
}

In swagger description TestIntAsString will be as string.

Enum

To write multiple possible values you mus use the tag "swagenum".

type TestStructWithStructField struct {
  TestStringEnum string `json:"testStringEnum" swagenum:"testEnum1,testEnum2,testEnum3"`
}

Examples

You can find examples of http-service in /example/. After run open in browser http://localhost:1323/api/v1/swagger/index.html

# Packages

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author