Swagger + Gin = SwaGin, a web framework based on Gin and Swagger

Overview

Swagger + Gin = SwaGin

deploy Go Reference

Introduction

SwaGin is a web framework based on Gin and Swagger, which wraps Gin and provides built-in swagger api docs and request model validation.

Why I build this project?

Previous I have used FastAPI, which gives me a great experience in api docs generation, because nobody like writing api docs.

Now I use Gin but I can't found anything like that, I found swag but which write docs with comment is so stupid. So there is SwaGin.

Installation

go get -u github.com/long2ice/swagin

Online Demo

You can see online demo at https://swagin.long2ice.io/docs or https://swagin.long2ice.io/redoc.

And you can reference all usage in examples.

Usage

Build Swagger

Firstly, build a swagger object with basic information.

package examples

import (
  "github.com/getkin/kin-openapi/openapi3"
  "github.com/long2ice/swagin/swagger"
)

func NewSwagger() *swagger.Swagger {
  return swagger.New("SwaGin", "Swagger + Gin = SwaGin", "0.1.0",
    swagger.License(&openapi3.License{
      Name: "Apache License 2.0",
      URL:  "https://github.com/long2ice/swagin/blob/dev/LICENSE",
    }),
    swagger.Contact(&openapi3.Contact{
      Name:  "long2ice",
      URL:   "https://github.com/long2ice",
      Email: "[email protected]",
    }),
    swagger.TermsOfService("https://github.com/long2ice"),
  )
}

Write API

Then make api struct which implement router.IAPI.

package examples

type TestQuery struct {
  Name string `query:"name" binding:"required" json:"name" description:"name of model" default:"test"`
}

func (t *TestQuery) Handler(c *gin.Context) {
  c.JSON(http.StatusOK, t)
}

Note that the attributes in TestQuery? SwaGin will validate request and inject it automatically, then you can use it in handler easily.

Write Router

Then write router with some docs configuration and api.

package examples

var query = router.New(
  &TestQuery{},
  router.Summary("Test Query"),
  router.Description("Test Query Model"),
  router.Tags("Test"),
)

Security

If you want to project your api with a security policy, you can use security, also they will be shown in swagger docs.

Current there is five kinds of security policies.

  • Basic
  • Bearer
  • ApiKey
  • OpenID
  • OAuth2
package main

var query = router.New(
  &TestQuery{},
  router.Summary("Test query"),
  router.Description("Test query model"),
  router.Security(&security.Basic{}),
)

Then you can get the authentication string by context.MustGet(security.Credentials) depending on your auth type.

package main

func (t *TestQuery) Handler(c *gin.Context) {
  user := c.MustGet(security.Credentials).(*security.User)
  fmt.Println(user)
  c.JSON(http.StatusOK, t)
}

Mount Router

Then you can mount router in your application or group.

package main

func main() {
  app := swagin.New(NewSwagger())
  queryGroup := app.Group("/query", swagin.Tags("Query"))
  queryGroup.GET("", query)
  queryGroup.GET("/:id", queryPath)
  queryGroup.DELETE("", query)
  app.GET("/noModel", noModel)
}

Start APP

Finally, start the application with routes defined.

package main

import (
  "github.com/gin-contrib/cors"
  "github.com/long2ice/swagin"
)

func main() {
  app := swagin.New(NewSwagger())
  app.Use(cors.New(cors.Config{
    AllowOrigins:     []string{"*"},
    AllowMethods:     []string{"*"},
    AllowHeaders:     []string{"*"},
    AllowCredentials: true,
  }))

  queryGroup := app.Group("/query", swagin.Tags("Query"))
  queryGroup.GET("", query)
  queryGroup.GET("/:id", queryPath)
  queryGroup.DELETE("", query)

  formGroup := app.Group("/form", swagin.Tags("Form"))
  formGroup.POST("/encoded", formEncode)
  formGroup.PUT("", body)

  app.GET("/noModel", noModel)
  app.POST("/body", body)
  if err := app.Run(); err != nil {
    panic(err)
  }
}

That's all! Now you can visit http://127.0.0.1:8080/docs or http://127.0.0.1:8080/redoc to see the api docs. Have fun!

Disable Docs

In some cases you may want to disable docs such as in production, just put nil to swagin.New.

app = swagin.New(nil)

SubAPP Mount

If you want to use sub application, you can mount another SwaGin instance to main application, and their swagger docs is also separate.

package main

func main() {
  app := swagin.New(NewSwagger())
  subApp := swagin.New(NewSwagger())
  subApp.GET("/noModel", noModel)
  app.Mount("/sub", subApp)
}

ThanksTo

  • kin-openapi, OpenAPI 3.0 implementation for Go (parsing, converting, validation, and more).
  • Gin, an HTTP web framework written in Go (Golang).

License

This project is licensed under the Apache-2.0 License.

Comments
  • Wrong Status Code Description

    Wrong Status Code Description

    Status code description is duplicated on all codes as shown in screenshot below:

    Capture d’écran_2022-02-08_11-20-04

    Router is defined as follows:

    var DeployProject = router.New(
    	&DeployProjectInput{},
    	router.Summary("Deploy Project"),
    	router.Description("Deploy project for given configuration"),
    	router.Responses(router.Response{
    		"204": router.ResponseItem{
    			Model:       model.Created{},
    			Description: "Project created",
    		},
    		"400": router.ResponseItem{
    			Model:       model.BadRequest{},
    			Description: "Bad request",
    		},
    		"404": router.ResponseItem{
    			Model:       model.NotFound{},
    			Description: "Not found",
    		},
    		"500": router.ResponseItem{
    			Model:       model.InternalServerError{},
    			Description: "Error response",
    		},
    	}),
    )
    
    opened by c4s4 7
  • go get -u github.com/long2ice/swagin error

    go get -u github.com/long2ice/swagin error

    Dear @long2ice,

    I stumbled across your interseting article as I was searching for a manner in which to serve an openapi.yaml swagger API instance using Gin. Thank you for taking the time to write such an in-depth article.

    When running the command go get -u github.com/long2ice/swagin it returns with the following error:

    $ go get -u github.com/long2ice/swagin
    go: downloading github.com/getkin/kin-openapi v0.80.0
    # github.com/long2ice/swagin/router
    /home/ben/go/pkg/mod/github.com/long2ice/[email protected]/router/router.go:31:14: c.ShouldBindRequest undefined (type *gin.Context has no field or method ShouldBindRequest)
    

    When following the error, it leads me to the below function in router/router.go:

    func BindModel(api IAPI) gin.HandlerFunc {
    	return func(c *gin.Context) {
    		if err := c.ShouldBindRequest(api); err != nil {
    			c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    			return
    		}
    		c.Next()
    	}
    }
    

    which is strange because when reading about gin.Context it takes you here:

    // Context is the most important part of gin. It allows us to pass variables between middleware,
    // manage the flow, validate the JSON of a request and render a JSON response for example.
    type Context struct {
    ...
    )
    

    Prior to having tried this I followed your guide and had quite a few errors. I then used the code that you had in: swagin/examples/ instead and got the exact same mistake as is already outlined here above.

    If you could please be so kind as to help me with this it'll be greatly appreciated :)

    Furthermore, the reason I'm wanting to make use of your repository - and as mentioned earlier - is because I want to serve my already generated openapi.yaml file using your repo. Is it possible to read a static yaml specification as opposed to a json specification? If so, how exactly would one go about this?

    Lastly, I'm not wanting to serve the openapi spec with the redoc method but rather the swagger method and as per this link: https://swagin.long2ice.io/docs

    Thanks in advance for your appreciated assistance.

    Kind regards,

    opened by BenWolfaardt 4
  • Enable OpenAPI in YAML format

    Enable OpenAPI in YAML format

    Adds YAML format for OpenAPI generated file. To do so, configure OpenAPIUrl with a path ending with .yml or .yaml, as follows:

    func NewSwagger() *swagger.Swagger {
    	return swagger.New(
    		...
    		swagger.OpenAPIUrl("/openapi.yml"),
    	)
    }
    

    When clicking on the link to the OpenAPI file in Swagger docuentation, this will return OpenAPI file in YAML format.

    opened by c4s4 3
  • Example doesn't build

    Example doesn't build

    When I try to build example in its own directory, I get:

    $ go build
    # github.com/long2ice/swagin/router
    ../../.go/pkg/mod/github.com/long2ice/[email protected]/router/router.go:31:14: c.ShouldBindRequest undefined (type *gin.Context has no field or method ShouldBindRequest)
    

    Swagin code calls method ShouldBindRequest() on Gin context but it doesn't exist in Gin code on official repository. This is defined in a fork on long2ice repository.

    File go.mod is as follows (generated with go mod tidy):

    module test
    
    go 1.17
    
    require (
    	github.com/getkin/kin-openapi v0.88.0
    	github.com/gin-contrib/cors v1.3.1
    	github.com/gin-gonic/gin v1.7.4
    	github.com/long2ice/swagin v0.1.0
    )
    
    require (
    	github.com/fatih/structtag v1.2.0 // indirect
    	github.com/ghodss/yaml v1.0.0 // indirect
    	github.com/gin-contrib/sse v0.1.0 // indirect
    	github.com/go-openapi/jsonpointer v0.19.5 // indirect
    	github.com/go-openapi/swag v0.19.5 // indirect
    	github.com/go-playground/locales v0.13.0 // indirect
    	github.com/go-playground/universal-translator v0.17.0 // indirect
    	github.com/go-playground/validator/v10 v10.4.1 // indirect
    	github.com/golang/protobuf v1.3.3 // indirect
    	github.com/json-iterator/go v1.1.9 // indirect
    	github.com/leodido/go-urn v1.2.0 // indirect
    	github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect
    	github.com/mattn/go-isatty v0.0.12 // indirect
    	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
    	github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
    	github.com/ugorji/go/codec v1.1.7 // indirect
    	golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
    	golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect
    	gopkg.in/yaml.v2 v2.3.0 // indirect
    )
    

    What is strange, is that it works if, in the Swagin project, I run:

    $ cd examples
    $ go build
    
    opened by c4s4 3
  • Added BindErrorManager

    Added BindErrorManager

    Added a BindErrorManager to handle bind errors, like so:

    var MyService = router.New(
    	...
    	router.BindErrorManager(BindErrorManager),
    )
    
    func BindErrorManager(ctx *gin.Context, err error) {
    	c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{...})
    }
    

    This way you can control errors when there is an error binding data to perform request.

    opened by c4s4 2
  • hot reload option

    hot reload option

    Quick question, is there a way to enable a "hot reload" kind of option? I'd read that gin run main.go --all does that trick when using the gin package directly, but I was not able to get that to work inside swagin

    I'm very new at Go and this package is helping me a lot moving from python (FastAPI) to Go, great work!!!

    opened by gsbecerrag 2
  • Crash on response struct with a map

    Crash on response struct with a map

    Let's consider following example code:

    package main
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    	"github.com/long2ice/swagin"
    	"github.com/long2ice/swagin/router"
    	"github.com/long2ice/swagin/swagger"
    )
    
    func main() {
    	app := swagin.New(swagger.New("SwaGin", "Swagger + Gin = SwaGin", "0.1.0"))
    	app.GET("/", test)
    	if err := app.Run(); err != nil {
    		panic(err)
    	}
    }
    
    var test = router.New(
    	&Input{},
    	router.Summary("Test query"),
    	router.Description("Test query model"),
    	router.Responses(router.Response{
    		"200": router.ResponseItem{
    			Model:       Response{},
    			Description: "Bug",
    		},
    	}),
    )
    
    type Input struct{}
    
    type Response struct {
    	Field map[string]string
    }
    
    func (t *Input) Handler(ctx *gin.Context) {
    	ctx.JSON(http.StatusOK, Response{})
    }
    

    If you run this code, il will crash in an infinite loop.

    opened by c4s4 1
  • Missing header

    Missing header

    In following example:

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"github.com/long2ice/swagin"
    	"github.com/long2ice/swagin/router"
    	"github.com/long2ice/swagin/swagger"
    )
    
    func main() {
    	app := swagin.New(swagger.New("SwaGin", "Swagger + Gin = SwaGin", "0.1.0"))
    	app.GET("/", test)
    	if err := app.Run(); err != nil {
    		panic(err)
    	}
    }
    
    var test = router.New(
    	&Test{},
    	router.Summary("Test query"),
    	router.Description("Test query model"),
    )
    
    type Test struct{
    	Authorization string `header:"authorization" binding:"required" json:"authorization" default:"authorization"`
    	Token string `header:"token" binding:"required" json:"token" default:"token"`
    }
    
    func (t *Test) Handler(ctx *gin.Context) {
    	println(">>>>>>>>>> authorization:", t.Authorization)
    	println(">>>>>>>>>> token:", t.Token)
    }
    

    I require two headers in request (Token and Authorization). They are both listed in documentation (at URL /docs) and I can set them to perform request. But validation fails for header Authorization which is missing, while Token is sent and received. Furthermore, in CURL example request Authorization header is missing while Token is set.

    In my opinion, both headers should be sent. Why is Authorization missing?

    This seems to be a collision with authorization bechanism in SwaGin, as it works fine with other headers.

    opened by c4s4 1
  • Panic recovery

    Panic recovery

    When a panic is raised in an handler, server doesn't catch and manage this panic to return a status 500 (Internal Server Error) response. Instead, it returns nothing to the client. This is demonstrated with this code:

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"github.com/long2ice/swagin"
    	"github.com/long2ice/swagin/router"
    	"github.com/long2ice/swagin/swagger"
    )
    
    func main() {
    	app := swagin.New(swagger.New("SwaGin", "Swagger + Gin = SwaGin", "0.1.0"))
    	app.GET("/", test)
    	if err := app.Run(); err != nil {
    		panic(err)
    	}
    }
    
    var test = router.New(
    	&Test{},
    	router.Summary("Test query"),
    	router.Description("Test query model"),
    )
    
    type Test struct{}
    
    func (t *Test) Handler(ctx *gin.Context) {
    	panic("test")
    }
    

    This can be fixed adding a recovery handler to the Gin engine. This handler will trap the panic and return appropriate response to client.

    opened by c4s4 1
  • Fix issue #6

    Fix issue #6

    This fixed issue #6 that happens when there are more than one response with different descriptions. All responses descriptions are overwritten with the last one.

    opened by c4s4 1
  • go get failed with gin v1.7.4

    go get failed with gin v1.7.4

    ❯ go get -u github.com/long2ice/swagin
    go: downloading github.com/long2ice/swagin v0.1.0
    go: downloading github.com/getkin/kin-openapi v0.72.0
    go: downloading github.com/getkin/kin-openapi v0.81.0
    go: downloading github.com/ghodss/yaml v1.0.0
    go: downloading github.com/go-openapi/swag v0.19.5
    go: downloading github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e
    # github.com/long2ice/swagin/router
    ../../go/pkg/mod/github.com/long2ice/[email protected]/router/router.go:31:14: c.ShouldBindRequest undefined (type *gin.Context has no field or method ShouldBindRequest)
    
    opened by yeluolei 1
  • x-codeSamples integration

    x-codeSamples integration

    This is more a question than an actual issue, but I think it is important to provide code samples to distribute the API docs directly in production, is there a way to use code sample objects? if anyone can point me in the right direction I can work in this functionality, as the official docs this object works like this in the API definition:

    Redocly Documentation

    openapi: '3.0'
    info: ...
    tags: [...]
    paths:
      /example:
        get:
          summary: Example summary
          description: Example description
          operationId: examplePath
          responses: [...]
          parameters: [...]
          x-codeSamples:
            - lang: 'cURL'
              label: 'CLI'
              source: |
                curl --request POST \
                --url 'https://data.apiexample.com/api/example/batch_query/json?format=json' \
                --header 'content-type: application/octet-stream: ' \
                --data '{}'
    
    opened by gsbecerrag 0
  • Integration tests

    Integration tests

    In order to check that code works as expected, I have coded integration tests using Venom. To run them:

    $ cd examples
    $ go test
    

    Tests are in files examples/test/.yml* and are quite self explanatory:

    request:
      url: "{{.URL}}/noModel"
      method: GET
    response:
      statusCode: 200
      json: null
    

    request entry describes request and response describes assertions made on response.

    Note that these tests pass on master branch but fail on dev. Adding them would be a great way to check automatically that everything works fine.

    opened by c4s4 0
  • Added function StartGraceful to star server with graceful shutdown

    Added function StartGraceful to star server with graceful shutdown

    You can start server with StartGraceful(addr...) function that sends back a server instance. You can call Shutdown() on this server instance to stop it gracefully.

    opened by c4s4 0
Releases(v0.1.0)
Percobaan membuat API dengan Golang menggunakan web framework Gin dan Swagger docs.

Percobaan Gin Framework Percobaan membuat API dengan bahasa Go-lang. Tech Stack Gin - Web framework Gin Swaggo - Swagger Docs integration for Gin web

Gabriel S 0 Feb 11, 2022
The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework.

jin About The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework. If thi

null 8 Jul 14, 2022
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.

Flamingo Framework Flamingo is a web framework based on Go. It is designed to build pluggable and maintainable web projects. It is production ready, f

Flamingo 317 Sep 27, 2022
Template/Starter code for Go application with Gin, System Tray, Gorm, Air, Swagger, JWT

gin-systray-starter Starter code for Go application with Gin, System Tray, Gorm, Air, Swagger, JWT systray, https://github.com/getlantern/systray gin,

jinyaoMa 1 Sep 16, 2022
Golanger Web Framework is a lightweight framework for writing web applications in Go.

/* Copyright 2013 Golanger.com. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except

golanger 299 Mar 3, 2022
A Go API project using Beego(Go Framework) with Swagger UI

Beego_API_with_swagger_UI Descriptions This is a Go API project using Beego(Go F

A.R partha 0 Dec 20, 2021
Gin is a HTTP web framework written in Go (Golang).

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.

Gin-Gonic 63.3k Oct 2, 2022
Rocinante is a gin inspired web framework built on top of net/http.

Rocinante Rocinante is a gin inspired web framework built on top of net/http. ⚙️ Installation $ go get -u github.com/fskanokano/rocinante-go ⚡️ Quicks

null 3 Jul 27, 2021
A gin-like simple golang web framework.

webgo A gin-like simple golang web framework.

vincent 1 Aug 24, 2022
A gin-like simple golang web framework.

A gin-like simple golang web framework.

vincent-言益 1 Aug 24, 2022
henrylee2cn 1.6k Sep 16, 2022
⚡ Rux is an simple and fast web framework. support middleware, compatible http.Handler interface. 简单且快速的 Go web 框架,支持中间件,兼容 http.Handler 接口

Rux Simple and fast web framework for build golang HTTP applications. NOTICE: v1.3.x is not fully compatible with v1.2.x version Fast route match, sup

Gookit 82 Sep 27, 2022
Roche is a Code Generator and Web Framework, makes web development super concise with Go, CleanArch

It is still under development, so please do not use it. We plan to release v.1.0.0 in the summer. roche is a web framework optimized for microservice

Riita 14 Sep 19, 2022
A powerful go web framework for highly scalable and resource efficient web application

webfr A powerful go web framework for highly scalable and resource efficient web application Installation: go get -u github.com/krishpranav/webfr Exa

Krisna Pranav 13 Nov 28, 2021
A powerful go web framework for highly scalable and resource efficient web application

A powerful go web framework for highly scalable and resource efficient web application

null 21 May 25, 2022
A web app built using Go Buffalo web framework

Welcome to Buffalo Thank you for choosing Buffalo for your web development needs. Database Setup It looks like you chose to set up your application us

Mike Okoth 0 Feb 7, 2022
gin auto binding,grpc, and annotated route,gin 注解路由, grpc,自动参数绑定工具

中文文档 Automatic parameter binding base on go-gin doc Golang gin automatic parameter binding Support for RPC automatic mapping Support object registrati

xxj 236 Sep 25, 2022
CRUD API server of Clean Architecture with Go(Echo), Gorm, MySQL, Docker and Swagger

CRUD API Server of Clean Architecture Go(echo) gorm mysql docker swagger build docker-compose up -d --build API Postman and Fiddler is recommended to

null 34 May 14, 2022
Go WhatsApp REST API Implementation Using Fiber And Swagger

Go WhatsApp REST API Implementation Using Fiber And Swagger Package cooljar/go-whatsapp-fiber Implements the WhatsApp Web API using Fiber web framewor

Mohammad Fajar Rizky 9 May 9, 2022