# README
Introduction
Maintaining API documentation and source code could be a cumbersome task
ginx is trying to solve the above problem by clear doc generation such that allowing developer to accelerate API prototyping
ginx is a lightweight extension to gin, which allows REST style API creation with OpenAPI 3.0.
The library is inspired by go-restful
Example
example.go
package main
import (
"github.com/gin-gonic/gin"
"github.com/raymond852/ginx"
"mime/multipart"
"net/http"
)
type exampleAPIIF interface {
ginx.API
JSONTest(ctx *gin.Context)
MultiPartFormTest(ctx *gin.Context)
FormUrlencodedTest(ctx *gin.Context)
}
func NewExampleAPI() exampleAPIIF {
return &exampleAPI{}
}
type exampleAPI struct {
}
func init() {
ginx.DocDefineRef("#EnumTest2Field", []interface{}{"val3", "val4"})
ginx.DocDefineRef("#DescTest2Field", "test2 field")
}
type MultipartFormRequest struct {
BoolField bool `form:"boolField" doc:"required desc(bool test)"`
Number float64 `form:"number" doc:"required desc(number test)"`
Integer int `form:"integer" doc:"required desc(integer test)"`
File multipart.FileHeader `form:"fileField" doc:"required desc(file to upload)"`
}
type UrlencodedFormRequest struct {
StringField string `form:"stringField" doc:"required desc(string field)"`
BoolField bool `form:"boolField" doc:"required desc(bool test)"`
Number float64 `form:"number" doc:"required desc(number test)"`
Integer int `form:"integer" doc:"required desc(integer test)"`
}
type JSONRequest struct {
JSONEmbed
EmailField string `json:"emailField" doc:"required format(email)"`
OuterStr string `json:"outerstr" doc:"required enum(val1;val2)"`
Test2 string `json:"test2" doc:"enum(#EnumTest2Field) desc(#DescTest2Field)"`
Number float64 `json:"number" doc:"required desc(number test)"`
Integer int `json:"integer" doc:"required desc(integer test) minimum(5) maximum(100)"`
Integer8 int8 `json:"integer8" doc:"desc(integer test)"`
Integer16 int16 `json:"integer16" doc:"desc(integer test)"`
Integer32 int32 `json:"integer32" doc:"desc(integer test)"`
Integer64 int64 `json:"integer64" doc:"desc(integer test)"`
}
type JSONEmbed struct {
Str string `json:"str" doc:"required desc(number test) pattern([^abc]+) maxLength(10) minLength(1)"`
Array []string `json:"arr" doc:"desc(array) minItems(1) maxItems(5)"`
}
type JSONResponse struct {
FieldOne string `json:"field1" doc:"desc(example field one)"`
FieldTwo bool `json:"field2" doc:"desc(example field 2)"`
}
func (e exampleAPI) RouteGroup() *ginx.RouteGroup {
docTag := "example"
rg := ginx.NewRouteGroup("/test")
rg.
Put("/json/:%s", "path").
To(e.JSONTest).
Doc().
Summary("json test").
Description("json test description").
Tag(docTag).
Header(ginx.Header("Test-Header").Schema("val1").Enum("val1", "val2").Description("Testing header")).
Query(ginx.Query("t").Schema("test").Required(false).Description("Testing query")).
Path(ginx.Path("path").Schema("path-test").Description("Testing path")).
RequestBody(ginx.JSONRequestBody(JSONRequest{
EmailField: "[email protected]",
JSONEmbed: JSONEmbed{
Str: "test",
Array: []string{"val1"},
},
OuterStr: "val1",
Test2: "val3",
Number: 10,
Integer: 12,
}).Required(true).Description("test JSON request body")).
Response("200", ginx.JSONResponseBody(JSONResponse{
FieldOne: "abc",
FieldTwo: false,
}), "success")
rg.
Post("/").
To(e.MultiPartFormTest).
Doc().
Summary("multipart form test").
Description("multipart form test description").
Tag(docTag).
RequestBody(ginx.MultiPartFormRequestBody(MultipartFormRequest{
Number: 10,
Integer: 100,
File: multipart.FileHeader{},
BoolField: true,
})).
Response("200", ginx.TextResponseBody("success"), "success")
rg.
Patch("/").
To(e.FormUrlencodedTest).
Doc().
Summary("urlencoded form test").
Description("urlencoded form test description").
Tag(docTag).
RequestBody(ginx.UrlEncodedFormRequestBody(UrlencodedFormRequest{
StringField: "string field",
BoolField: false,
Number: 1,
Integer: 2,
})).
Response("200", ginx.TextResponseBody("success"), "success")
return rg
}
func (e exampleAPI) JSONTest(ctx *gin.Context) {
ctx.AbortWithStatusJSON(http.StatusOK, JSONResponse{
FieldOne: "fieldOne",
FieldTwo: false,
})
}
func (e exampleAPI) MultiPartFormTest(ctx *gin.Context) {
req := &MultipartFormRequest{}
if err := ctx.ShouldBind(req); err != nil {
ctx.String(http.StatusBadRequest, "bad request")
ctx.Abort()
} else {
ctx.String(http.StatusOK, "success")
ctx.Abort()
}
}
func (e exampleAPI) FormUrlencodedTest(ctx *gin.Context) {
req := &UrlencodedFormRequest{}
if err := ctx.ShouldBind(req); err != nil {
ctx.String(http.StatusBadRequest, "bad request")
ctx.Abort()
} else {
ctx.String(http.StatusOK, "success")
ctx.Abort()
}
}
main.go
package main
import (
"github.com/raymond852/ginx"
"github.com/gin-gonic/gin"
"mime/multipart"
"net/http"
"net/url"
"strings"
"testing"
"time"
"bytes"
"net/http"
)
func main(){
g := gin.New()
ginx.Init("example description", "1.0.0", "An example title")
ginx.UseSwaggerUI(g, "/apidoc")
ginx.UseValidator(g, func(ctx *gin.Context, err error) {
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, map[string]interface{}{
"error": err.Error(),
})
}
})
ginx.AddAPI(g, NewExampleAPI())
srv := &http.Server{
Addr: ":5699",
Handler: g,
}
_ = srv.ListenAndServe()
}
Swagger UI gin middleware
gin.UseSwaggerUI
open browser and go to http://localhost:5699/apidoc and you will able to browse the Swagger doc
OpenAPI 3.0 request validator gin middleware
ginx.UseValidator
the middleware will validate the request against the OpenAPI 3.0 spec
Features
- Tag for generate request body and response body which align with openapi 3.0 spec
- Request validation
- Open API 3.0 doc generation and preview using swagger UI
# Functions
No description provided by the author
Asset loads and returns the asset for the given name.
AssetDir returns the file names below a certain directory embedded in the file by go-bindata.
AssetFile return a http.FileSystem instance that data backend by asset.
AssetInfo loads and returns the asset info for the given name.
AssetNames returns the names of the assets.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
MustAsset is like Asset but panics when Asset would return an error.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
RestoreAsset restores an asset under the given directory.
RestoreAssets restores an asset under the given directory recursively.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
# Constants
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
# Structs
No description provided by the author
# Interfaces
No description provided by the author