Documentation ¶
Overview ¶
A MVC binder for free-style of function handler with *gin.Context
Abstract ¶
There are may tedious processes for coding on web service:
- Type conversion from HTTP query parameter to desired type in GoLang.
- Binding body of HTTP POST to JSON object in GoLang. 2.1. Perform post-process(e.x. trim text) of binding data 2.2. Perform data validation of binding data
- Convert the result data to JSON response.
Gin has provided foundation features on simple and versatile web application, this framework try to enhance the building of web application on instinct way.
MVC Handler ¶
A MVC handler can be any function with ruled types of parameter and defined returned types.
type MvcHandler interface{}
You can define handler of supported:
func(req *http.Request, params *gin.Params) OutputBody { /* ... */ return TextOutputBody("Hello World") } func( data *struct { Name string `mvc:"query[name]"` Age int `mvc:"query[age]"` SessionId string `mvc:"header[session_id"` } ) OutputBody { /* ... */ return TextOutputBody("Hello World") }
Build Gin HandlerFunc ¶
After you define the MVC handler, you could use "MvcBuilder.BuildHandler()" to convert your handler to "gin.HandlerFunc".
mvcBuilder := NewMvcBuilder(NewDefaultMvcConfig()) engine.Get("/your-web-service", mvcBuilder.BuildHandler(your_mvc_handler))
Parameters of Handler ¶
Supported types:
"ContextBinder" - Feeds the context to implementation of Bind(*gin.Context) function.
This type of value woule be checked by ogin.ConformAndValidateStruct automatically.
'json.Unmarshaler' - If the type of value is json.Unmarshaler, use the UnmarshalJSON([]byte) function of the value
This type of value woule be checked by ogin.ConformAndValidateStruct automatically.
"<struct>" - See parameter tags for automatic binding
This type of value woule be checked by ogin.ConformAndValidateStruct automatically.
"*gin.Context" - The context object of current request
"gin.ResponseWriter" - See gin.ResponseWriter
"gin.Params" - See gin.Params
"*http.Request" - See http.Request
"http.ResponseWriter" - See http.ResponseWriter
"*url.URL" - See url.URL
"*multipart.Reader" - See multipart.Reader; Once you use *multipart.Form, the reader would reach EOF.
"*multipart.Form" - See multipart.Form
"*validator.Validate" - See go-playground/validator.v9
"types.ConversionService" - See ConversionService
Return value of Handler ¶
"OutputBody" is the main definition for output of web service, it has build-in functions for certain types of output:
"JsonOutputBody()" - Uses gin.Context.JSON function to perform output "TextOutputBody()" - Uses gin.Context.String function to generate output body(by fmt.Sprintf("%v")) "HtmlOutputBody()," XmlOutputBody(), YamlOutpuBody() - Calls function of gin.Context, respectively.
"json.Marshaler" - If the type of returned value is json.Marshaler, use JsonOutputBody() as output type
"string" - If the type of returned value is string, use TextOutputBody() as output type
"fmt.Stringer" - As same as string
"*model.Paging" - Output the content of paging to HTTP header
Tagging Struct ¶
There are various definition of tags could be used on struct:
type MyData struct { Name string `mvc:"query[name] default[NO-NAME]"` H1 string `mvc:"header[h1]"` FormV1 int `mvc:"form[v1]"` FormV3 []string `mvc:"form[v2]"` // As slice File1 multipart.File `mvc:"file[f1]"` File2 multipart.File `mvc:"file[f2]"` }
Default Value
mvc:"query[param_name_1] default[20]" - Gives value 20 if the value of binding is empty mvc:"query[param_name_1] default[20,40,30]" - Gives value [20, 40, 30](as array, no space)if the value of binding is empty
Parameters, Heaer, Cookie, and From
mvc:"query[param_name_1]" - Use query parameter param_name_1 as binding value mvc:"query[?param_name_1]" - Must be bool type, used to indicate whether or not has viable value for this parameter mvc:"cookie[ck_1]" - Use the value of cookie ck_1 as binding value mvc:"cookie[?ck_2]" - Must be bool type, used to indicate whether or not has viable value for this parameter mvc:"param[pm_1]" - Use the value of URI parameter pm_1 as binding value mvc:"form[in_1]" - Use the form value of in_1 as binding value mvc:"form[?in_2]" - Must be bool type, used to indicate whether or not has viable value for this parameter mvc:"header[Content-Type]" - Use the header value of Content-Type as binding value mvc:"header[?pg_id]" - Must be bool type, used to indicate whether or not has viable value for this parameter mvc:"key[key-1]" - Use the key value of key-1 as binding value mvc:"key[?key-3]" - Must be bool type, used to indicate whether or not has viable value for this parameter
By default, if the value of binding is existing, the framework would use the default value of binding type.
HTTP
mvc:"req[ClientIp]" - The IP of client, the type of value could be string or net.IP mvc:"req[ContentType]" - The content type of request, must be string mvc:"req[Referer]" - The "Referer" of request, must be string mvc:"req[UserAgent]" - The "User-Agent" of request, must be string mvc:"req[Method]" - The method of request, must be string mvc:"req[Url]" - The url of reqeust, must be string or url.URL mvc:"req[Proto]" - The protocol version for incoming server requests, must be string mvc:"req[ProtoMajor]" - The protocol version for incoming server requests, must be int mvc:"req[ProtoMinor]" - The protocol version for incoming server requests, must be int mvc:"req[ContentLength]" - The ContentLength? records the length of the associated content, must be int64 mvc:"req[Host]" - For server requests Host specifies the host on which the URL is sought, must be string mvc:"req[RemoteAddr]" - RemoteAddr allows HTTP servers and other software to record the network address that sent the request, usually for logging, must be string mvc:"req[RequestURI]" - RequestURI is the unmodified Request-URI of the Request-Line (RFC 2616, Section 5.1) as sent by the client to a server, must be string
PAGING
Must be type of "*model.Paging"
mvc:"pageSize[50]" - The default value of page size is 50 mvc:"pageOrderBy[name:age]" - The default value of "orderBy" property of paging object is 'name:age'
SECURITY
mvc:"basicAuth[username]" - The username of BasicAuth?, See RFC-2617 mvc:"basicAuth[password]" - The password of BasicAuth?, See RFC-2617
FILE UPLOAD
mvc:"file[f1]" - The file of request by key value, must be "multipart.File"(or "[]multipart.File") You don't have to close this resource, Gin MVC would do your favour. mvc:"fileHeader[f1]" - The file header of request by key value, must be "*multipart.FileHeader"(or "[]*multipart.FileHeader")
Data Conversion ¶
This framework depends on ConversionService to perform type conversion ¶
Data Validation ¶
For struct type of input parameter, this framework would use "MvcConfig.Validator" and "common/conform" to perform post-process on the parameter and validate it.
See go-playground/validator: https://godoc.org/gopkg.in/go-playground/validator.v9
See leebenson/conform: https://github.com/leebenson/conform
Index ¶
- Variables
- type ContextBinder
- type ContextBinderFunc
- type MvcBuilder
- type MvcConfig
- type MvcHandler
- type OutputBody
- func HtmlOutputBody(name string, v interface{}) OutputBody
- func HtmlOutputBody2(code int, name string, v interface{}) OutputBody
- func HtmlOutputOrNotFound(name string, v interface{}) OutputBody
- func JsonOutputBody(v interface{}) OutputBody
- func JsonOutputBody2(code int, v interface{}) OutputBody
- func JsonOutputOrNotFound(v interface{}) OutputBody
- func TextOutputBody(v interface{}) OutputBody
- func TextOutputBody2(code int, v interface{}) OutputBody
- func TextOutputOrNotFound(v interface{}) OutputBody
- func XmlOutputBody(v interface{}) OutputBody
- func XmlOutputBody2(code int, v interface{}) OutputBody
- func XmlOutputOrNotFound(v interface{}) OutputBody
- func YamlOutputBody(v interface{}) OutputBody
- func YamlOutputBody2(code int, v interface{}) OutputBody
- func YamlOutputOrNotFound(v interface{}) OutputBody
- type OutputBodyFunc
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var NotFoundOutputBody = OutputBodyFunc(func(c *gin.Context) { ogin.JsonNoRouteHandler(c) })
Functions ¶
This section is empty.
Types ¶
type ContextBinder ¶
Main interface for binding context
type ContextBinderFunc ¶
Function type of "ContextBuilder"
func (ContextBinderFunc) Bind ¶
func (f ContextBinderFunc) Bind(context *gin.Context)
type MvcBuilder ¶
type MvcBuilder struct {
// contains filtered or unexported fields
}
Builder object with internal objects
func NewMvcBuilder ¶
func NewMvcBuilder(newConfig *MvcConfig) *MvcBuilder
Constructs a new builder with configuration
func (*MvcBuilder) BuildHandler ¶
func (b *MvcBuilder) BuildHandler(handlerFunc MvcHandler) gin.HandlerFunc
Example (HttpGet) ¶
mvcBuilder := NewMvcBuilder(NewDefaultMvcConfig()) gin.SetMode(gin.ReleaseMode) engine := gin.New() engine.GET( "/get-1", mvcBuilder.BuildHandler( func( data *struct { V1 int8 `mvc:"query[v1]"` V2 int32 `mvc:"query[v2]"` }, ) string { return fmt.Sprintf("V1: %d. V2: %d", data.V1, data.V2) }, ), ) req := httptest.NewRequest(http.MethodGet, "/get-1?v1=20&v2=40", nil) resp := httptest.NewRecorder() engine.ServeHTTP(resp, req) fmt.Println(resp.Body.String())
Output: V1: 20. V2: 40
Example (HttpPost) ¶
mvcBuilder := NewMvcBuilder(NewDefaultMvcConfig()) gin.SetMode(gin.ReleaseMode) engine := gin.New() engine.POST( "/post-1", mvcBuilder.BuildHandler( func( data *struct { V1 int8 `mvc:"form[v1]"` V2 []int32 `mvc:"form[v2]"` }, ) string { return fmt.Sprintf("v1: %d. v2: %d,%d", data.V1, data.V2[0], data.V2[1]) }, ), ) /** * Form data */ form := url.Values{ "v1": []string{"17"}, "v2": []string{"230", "232"}, } // :~) req := httptest.NewRequest(http.MethodPost, "/post-1", strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp := httptest.NewRecorder() engine.ServeHTTP(resp, req) fmt.Println(resp.Body.String())
Output: v1: 17. v2: 230,232
Example (Json) ¶
/* type sampleCar struct { Name string `json:"name"` Age int `json:"age"` } func (car *sampleCar) Bind(c *gin.Context) { ogin.BindJson(c, car) } */ mvcBuilder := NewMvcBuilder(NewDefaultMvcConfig()) gin.SetMode(gin.ReleaseMode) engine := gin.New() engine.POST( "/json-1", mvcBuilder.BuildHandler( func(car *sampleCar) OutputBody { return JsonOutputBody(car) }, ), ) rawJson, _ := json.Marshal(&sampleCar{"GTA-99", 3}) req := httptest.NewRequest(http.MethodPost, "/json-1", bytes.NewReader(rawJson)) req.Header.Set("Content-Type", "application/json") resp := httptest.NewRecorder() engine.ServeHTTP(resp, req) fmt.Println(resp.Body.String())
Output: {"name":"GTA-99","age":3}
Example (Paging) ¶
mvcBuilder := NewMvcBuilder(NewDefaultMvcConfig()) gin.SetMode(gin.ReleaseMode) engine := gin.New() engine.GET( "/paging-1", mvcBuilder.BuildHandler( func( p *struct { // Loads paging from header Paging *model.Paging }, ) (*model.Paging, string) { p.Paging.TotalCount = 980 // Output paging in header return p.Paging, fmt.Sprintf("Position: %d", p.Paging.Position) }, ), ) req := httptest.NewRequest(http.MethodGet, "/paging-1", nil) // Ask for page of 4th req.Header.Set("page-pos", "4") resp := httptest.NewRecorder() engine.ServeHTTP(resp, req) fmt.Println(resp.Body.String()) fmt.Printf("total-count: %s", resp.Header().Get("total-count"))
Output: Position: 4 total-count: 980
type MvcConfig ¶
type MvcConfig struct { // ConversionServer used to perform type conversion ConvertService ot.ConversionService // Validator object used to perform data validations Validator *validator.Validate }
Defines configuration of MVC framework
func NewDefaultMvcConfig ¶
func NewDefaultMvcConfig() *MvcConfig
Constructs default configuration of MVC framework
type OutputBody ¶
Main interface for generating response
func HtmlOutputBody ¶
func HtmlOutputBody(name string, v interface{}) OutputBody
Uses "(*gin.Context).HTML(http.StatusOK, name, v)" to perform response
func HtmlOutputBody2 ¶
func HtmlOutputBody2(code int, name string, v interface{}) OutputBody
Uses "(*gin.Context).HTML(code, name, v)" to perform response
func HtmlOutputOrNotFound ¶
func HtmlOutputOrNotFound(name string, v interface{}) OutputBody
Output the value or not found error if the value is not viable
func JsonOutputBody ¶
func JsonOutputBody(v interface{}) OutputBody
Uses "(*gin.Context).JSON(http.StatusOK, v)" to perform response
func JsonOutputBody2 ¶
func JsonOutputBody2(code int, v interface{}) OutputBody
Uses "(*gin.Context).JSON(code, v)" to perform response
func JsonOutputOrNotFound ¶
func JsonOutputOrNotFound(v interface{}) OutputBody
Output the value or not found error if the value is not viable
func TextOutputBody ¶
func TextOutputBody(v interface{}) OutputBody
Uses "(*gin.Context).String(http.StatusOK, v)" to perform response
func TextOutputBody2 ¶
func TextOutputBody2(code int, v interface{}) OutputBody
Uses "(*gin.Context).String(code, v)" to perform response
func TextOutputOrNotFound ¶
func TextOutputOrNotFound(v interface{}) OutputBody
Output the value or not found error if the value is not viable
func XmlOutputBody ¶
func XmlOutputBody(v interface{}) OutputBody
Uses "(*gin.Context).XML(http.StatusOK, v)" to perform response
func XmlOutputBody2 ¶
func XmlOutputBody2(code int, v interface{}) OutputBody
Uses "(*gin.Context).XML(code, v)" to perform response
func XmlOutputOrNotFound ¶
func XmlOutputOrNotFound(v interface{}) OutputBody
Output the value or not found error if the value is not viable
func YamlOutputBody ¶
func YamlOutputBody(v interface{}) OutputBody
Uses "(*gin.Context).YAML(http.StatusOK, v)" to perform response
func YamlOutputBody2 ¶
func YamlOutputBody2(code int, v interface{}) OutputBody
Uses "(*gin.Context).YAML(code, v)" to perform response
func YamlOutputOrNotFound ¶
func YamlOutputOrNotFound(v interface{}) OutputBody
Output the value or not found error if the value is not viable
type OutputBodyFunc ¶
Function version of "OutputBody"
func (OutputBodyFunc) Output ¶
func (f OutputBodyFunc) Output(context *gin.Context)
As implementation of "OutputBody"