gin

package module
v0.0.0-...-d6ccb58 Latest Latest
Warning

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

Go to latest
Published: Jun 18, 2022 License: LGPL-3.0-or-later Imports: 11 Imported by: 0

README

package: github.com/mikelue/go-misc/ioc/gin GoDoc for API references.

This MVC framework is based on Gin.

Configuration and MvcBuilder

config := igin.NewMvcConfig().
    RegisterParamResolvers(...).
    RegisterErrorHandlers(...)

builder := config.ToBuilder()

Wrap customized handler

You can use struct tag to inject parameter for your hander.


type YourParams struct {
    Id int `json:"id"`
    Name string `json:"name"`
}

func yourHandler(params &YourParams) OutputBody {
    // Use params to process your function

    return OutputBody(http.StatusOK, yourData)
}

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:

  1. Type conversion from HTTP query parameter to desired type in GoLang.
  2. 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
  3. 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.

MvcHandler

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) OutputHandler {
    return TextOutputHandler("Hello World")
}

func(
    data *struct {
        // Binding data from form(or query string)
        Name string `form:"name" default:"anonymous"`
        // Binding data from uri
        Age int `uri:"id" default:"0"`
        // Binding data from header
        SessionId string `header:"session_id"`
        // Binding data from JSON
        Weight int `json:"weight"`
    },
) OutputHandler {
    return TextOutputHandler("Hello World")
}

WrapToGinHandler

After you define the MVC handler, you could use "MvcBuilder.WrapToGinHandler()" to convert your handler to "gin.HandlerFunc".

mvcBuilder := NewMvcConfig().ToBuilder()
engine.Get("/your-web-service", mvcBuilder.WrapToGinHandler(your_mvc_handler))

Parameters of Handler

"<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

TODO-Parameters of Handler

"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.

"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.v10

Tagging Struct

There are various definition of tags could be used on struct:

type MyData struct {
    // Binding data from form(or query string)
    Name string `form:"name"`
    // Binding data from uri
    Age int `uri:"id"`
    // Binding data from header
    SessionId string `header:"session_id"`
    // Binding data from JSON
    Weight int `json:"weight"`
}

Form(Query string), header, or JSON body

form:"field_1" - Use query parameter param_name_1 as binding value
form:"field_2" - Must be bool type, used to indicate whether or not has viable value for this parameter
header:"header_value_1" - Use the value of URI parameter pm_1 as binding value
header:"header_value_2" - Use the form value of in_1 as binding value
uri:"uri_v_1" - Must be bool type, used to indicate whether or not has viable value for this parameter
uri:"uri_v_2" - Use the header value of Content-Type as binding value
json:"v1" - Must be bool type, used to indicate whether or not has viable value for this parameter
json:"v2" - Must be bool type, used to indicate whether or not has viable value for this parameter

TODO-Default Value

default:"20" - Gives value 20 if the value of binding is empty
default:"[20,40,30]" - Gives value [20, 40, 30](as array, no space)if the value of binding is empty

By default, if the value of binding is existing, the framework would use the default value of binding type.

Data Validation

The Gin framework uses "go-playground/validator"(v10) as default validator.

See Also: Documentations of Gin's Binding: https://github.com/gin-gonic/gin#model-binding-and-validation

You can register "ErrorHandler" to resolve errors comes from "MvcHandler"

See

"MvcConfig.RegisterErrorHandlers(ErrorHandler)"

OutputHandler

You can provides various combination of returned value for "MvcHandler":

OutputHandler - Single value of output body
(OutputHandler, error) - OutputHandler nad error
(OutputHandler, int) - response status and OutputHandler
(OutputHandler, int, error) - response status, OutputHandler, and error

Implements "OutputHandler"

You can implements "OutputHandler" of returned type:

type MyCar struct {}
func (self *MyUser) Output(context *gin.Context) error {
  context.JSON(200, "[1, 11, 21]")
  return nil
}

func yourHandler() *MyCar {
  return nil
}

see: "JsonOutputHandler", "TextOutputHandler", "XmlOutputHandler", etc.

TODO-Return value by other types

"json.Marshaler" - If the type of returned value is json.Marshaler, use JsonOutputHandler() as output type

"string" - If the type of returned value is string, use TextOutputHandler() as output type

"fmt.Stringer" - As same as string

Index

Examples

Constants

View Source
const (
	DEFAULT_TIMEOUT = 5
)

Variables

This section is empty.

Functions

This section is empty.

Types

type ErrorHandler

type ErrorHandler interface {
	// Checks whether or not the error bould be resolved
	CanHandle(*gin.Context, error) bool
	// Handles the error
	HandleError(*gin.Context, error) error
}

Process and resolves the generated error by MvcHandler

type MvcBuilder

type MvcBuilder interface {
	// The wrapper method
	WrapToGinHandler(MvcHandler) func(c *gin.Context)
}

This build warp MVC handler to gin handler(as "func(c *gin.Context)")

Example (WrapToGinHandler)
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
)

func main() {
	/**
	 * Prepares request
	 */
	req := httptest.NewRequest(
		"POST", "/sample-uri",
		strings.NewReader(`{ "id": 281, "color": 3 , "code": "IU-762"}`),
	)

	req.Header.Set("Content-Type", "application/json")

	sampleContext, resp := newContext()
	sampleContext.Request = req
	// :~)

	/**
	 * Wraps the customized handler
	 */
	handler := NewMvcConfig().ToBuilder().
		WrapToGinHandler(sampleHandler)
	handler(sampleContext)
	// :~)

	fmt.Printf("Resp[%d]: %s", resp.Code, resp.Body.String())
}

type leopard struct {
	Id    int    `json:"id"`
	Color uint8  `json:"color"`
	Code  string `json:"code"`
}

func sampleHandler(leopard *leopard) OutputHandler {
	sampleOutput := []interface{}{
		10, 20, leopard.Code,
	}

	return JsonOutputHandler(http.StatusOK, sampleOutput)
}
Output:

Resp[200]: [10,20,"IU-762"]

type MvcConfig

type MvcConfig struct {
	// contains filtered or unexported fields
}

The configuration used by "MvcBuilder"

func NewMvcConfig

func NewMvcConfig() *MvcConfig

Constructs MVC configuration with default values

EnableValidator(bool) - true
Example (ToBuilder)
builder := NewMvcConfig().ToBuilder()
_ = builder
Output:

func (*MvcConfig) RegisterErrorHandlers

func (self *MvcConfig) RegisterErrorHandlers(errHandlers ...ErrorHandler) *MvcConfig

Registers multiple handlers for error

By default, any unhandled error would be output as JSON and 500(Internal server error) status

func (*MvcConfig) RegisterParamAsFieldResolvers

func (self *MvcConfig) RegisterParamAsFieldResolvers(paramAsFieldResolvers ...ParamAsFieldResolver) *MvcConfig

Registers multiple resolvers of field

func (*MvcConfig) RegisterParamResolvers

func (self *MvcConfig) RegisterParamResolvers(paramResolvers ...ParamResolver) *MvcConfig

Registers multiple resolvers

func (*MvcConfig) ToBuilder

func (self *MvcConfig) ToBuilder() MvcBuilder

Gets the instance of "MvcBuilder"

type MvcHandler

type MvcHandler = interface{}

As alias for "interface{}"(GoLang Sucks)

type OutputHandler

type OutputHandler interface {
	Output(*gin.Context) error
}

Main interface for generating response

Example
package main

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
)

type text3OutputHandler struct{}

func (*text3OutputHandler) Output(context *gin.Context) error {
	context.Data(http.StatusUseProxy, "plain/text", []byte("hello world"))
	return nil
}

func text3Handler() OutputHandler {
	return &text3OutputHandler{}
}

func main() {
	/**
	 * Prepares request
	 */
	sampleContext, resp := newContext()
	// :~)

	/**
	 * Wraps the customized handler
	 */
	handler := NewMvcConfig().ToBuilder().
		WrapToGinHandler(text3Handler)
	handler(sampleContext)
	// :~)

	fmt.Printf("Resp[%d]: %s", resp.Code, resp.Body.String())
}
Output:

Resp[305]: hello world

func AutoDetectOutputHandler

func AutoDetectOutputHandler(code int, v interface{}) OutputHandler

With HTTP header of "Accepted", this function builds "OutputHandler" by the supported MIME type:

 application/json, application/xml, text/xml, text/plain,
	application/x-protobuf, application/x-yaml

func HtmlOutputHandler

func HtmlOutputHandler(code int, name string, v interface{}) OutputHandler

Uses "(*gin.Context).HTML(code, name, v)" to perform response

func JsonOutputHandler

func JsonOutputHandler(code int, v interface{}) OutputHandler

Uses "(*gin.Context).JSON(http.StatusOK, v)" to perform response

func ProtoBufOutputHandler

func ProtoBufOutputHandler(code int, v interface{}) OutputHandler

Uses "(*gin.Context).ProtoBuf(code, v)" to perform response

func TextOutputHandler

func TextOutputHandler(code int, v interface{}) OutputHandler

Uses "(*gin.Context).String(code, v)" to perform response

func XmlOutputHandler

func XmlOutputHandler(code int, v interface{}) OutputHandler

Uses "(*gin.Context).XML(code, v)" to perform response

func YamlOutputHandler

func YamlOutputHandler(code int, v interface{}) OutputHandler

Uses "(*gin.Context).YAML(code, v)" to perform response

type OutputHandlerFunc

type OutputHandlerFunc func(*gin.Context) error

Functional type of "OutputHandler"

Example
package main

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
)

func text3OutputFunc(context *gin.Context) error {
	context.Data(http.StatusNotAcceptable, "plain/text", []byte("This is fine"))
	return nil
}

func text3HandlerByFunc() OutputHandler {
	return OutputHandlerFunc(text3OutputFunc)
}

func main() {
	/**
	 * Prepares request
	 */
	sampleContext, resp := newContext()
	// :~)

	/**
	 * Wraps the customized handler
	 */
	handler := NewMvcConfig().ToBuilder().
		WrapToGinHandler(text3OutputFunc)
	handler(sampleContext)
	// :~)

	fmt.Printf("Resp[%d]: %s", resp.Code, resp.Body.String())
}
Output:

Resp[406]: This is fine

func (OutputHandlerFunc) Output

func (f OutputHandlerFunc) Output(context *gin.Context) error

As implementation of "OutputHandler"

type ParamAsFieldResolver

type ParamAsFieldResolver interface {
	// Checks whether or not the value of field could be resolved
	CanResolve(*reflect.StructField) bool
	// Constructs and initializes the value of the struct's field
	Resolve(*gin.Context, *reflect.StructField) (interface{}, error)
}

Constructs and resolves parameter(for field of struct) fed to "MvcHandler"

type ParamResolver

type ParamResolver interface {
	// Checks whether or not the type of value could be resolved
	CanResolve(reflect.Type) bool
	// Constructs and initializes the value of parameter
	Resolve(*gin.Context, reflect.Type) (interface{}, error)
}

Constructs and resolves parameter fed to "MvcHandler"

type Resolvable

type Resolvable interface {
	Resolve(*gin.Context) error
}

A type could implements this interface to customize resolving

type ResolvableField

type ResolvableField interface {
	ResolveField(*gin.Context, *reflect.StructField) error
}

A type could implements this interface to customize resolving when it is enclosed as field of a struct

type StoppableServer

type StoppableServer struct {
	// contains filtered or unexported fields
}

Provides methods to shutdown server gracefully.

func NewStoppableServer

func NewStoppableServer(newEngine *gin.Engine) *StoppableServer

Constructs a new instance of "*StoppableServer" with "*gin.Engine"

func (*StoppableServer) ListenAndServeAsync

func (self *StoppableServer) ListenAndServeAsync(addr string)

Starts server

func (*StoppableServer) Shutdown

func (self *StoppableServer) Shutdown()

Shutdowns server with 5 seconds timeout by default.

func (*StoppableServer) ShutdownWithTimeout

func (self *StoppableServer) ShutdownWithTimeout(duration time.Duration)

Shutdowns server with timeout.

Jump to

Keyboard shortcuts

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