github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin/README.md (about)

     1  # Gin Web Framework
     2  
     3  <img align="right" width="159px" src="https://raw.githubusercontent.com/gin-gonic/logo/master/color.png">
     4  
     5  [![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)
     6  [![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin)
     7  [![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin)
     8  [![GoDoc](https://pkg.go.dev/badge/github.com/gin-gonic/gin?status.svg)](https://pkg.go.dev/github.com/gin-gonic/gin?tab=doc)
     9  [![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
    10  [![Sourcegraph](https://sourcegraph.com/github.com/gin-gonic/gin/-/badge.svg)](https://sourcegraph.com/github.com/gin-gonic/gin?badge)
    11  [![Open Source Helpers](https://www.codetriage.com/gin-gonic/gin/badges/users.svg)](https://www.codetriage.com/gin-gonic/gin)
    12  [![Release](https://img.shields.io/github/release/gin-gonic/gin.svg?style=flat-square)](https://github.com/gin-gonic/gin/releases)
    13  [![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/gin-gonic/gin)](https://www.tickgit.com/browse?repo=github.com/gin-gonic/gin)
    14  
    15  Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.
    16  
    17  
    18  ## Contents
    19  
    20  - [Gin Web Framework](#gin-web-framework)
    21    - [Contents](#contents)
    22    - [Installation](#installation)
    23    - [Quick start](#quick-start)
    24    - [Benchmarks](#benchmarks)
    25    - [Gin v1. stable](#gin-v1-stable)
    26    - [Build with jsoniter](#build-with-jsoniter)
    27    - [API Examples](#api-examples)
    28      - [Using GET, POST, PUT, PATCH, DELETE and OPTIONS](#using-get-post-put-patch-delete-and-options)
    29      - [Parameters in path](#parameters-in-path)
    30      - [Querystring parameters](#querystring-parameters)
    31      - [Multipart/Urlencoded Form](#multiparturlencoded-form)
    32      - [Another example: query + post form](#another-example-query--post-form)
    33      - [Map as querystring or postform parameters](#map-as-querystring-or-postform-parameters)
    34      - [Upload files](#upload-files)
    35        - [Single file](#single-file)
    36        - [Multiple files](#multiple-files)
    37      - [Grouping routes](#grouping-routes)
    38      - [Blank Gin without middleware by default](#blank-gin-without-middleware-by-default)
    39      - [Using middleware](#using-middleware)
    40      - [How to write log file](#how-to-write-log-file)
    41      - [Custom Log Format](#custom-log-format)
    42      - [Controlling Log output coloring](#controlling-log-output-coloring)
    43      - [Model binding and validation](#model-binding-and-validation)
    44      - [Custom Validators](#custom-validators)
    45      - [Only Bind Query String](#only-bind-query-string)
    46      - [Bind Query String or Post Data](#bind-query-string-or-post-data)
    47      - [Bind Uri](#bind-uri)
    48      - [Bind Header](#bind-header)
    49      - [Bind HTML checkboxes](#bind-html-checkboxes)
    50      - [Multipart/Urlencoded binding](#multiparturlencoded-binding)
    51      - [XML, JSON, YAML and ProtoBuf rendering](#xml-json-yaml-and-protobuf-rendering)
    52        - [SecureJSON](#securejson)
    53        - [JSONP](#jsonp)
    54        - [AsciiJSON](#asciijson)
    55        - [PureJSON](#purejson)
    56      - [Serving static files](#serving-static-files)
    57      - [Serving data from file](#serving-data-from-file)
    58      - [Serving data from reader](#serving-data-from-reader)
    59      - [HTML rendering](#html-rendering)
    60        - [Custom Template renderer](#custom-template-renderer)
    61        - [Custom Delimiters](#custom-delimiters)
    62        - [Custom Template Funcs](#custom-template-funcs)
    63      - [Multitemplate](#multitemplate)
    64      - [Redirects](#redirects)
    65      - [Custom Middleware](#custom-middleware)
    66      - [Using BasicAuth() middleware](#using-basicauth-middleware)
    67      - [Goroutines inside a middleware](#goroutines-inside-a-middleware)
    68      - [Custom HTTP configuration](#custom-http-configuration)
    69      - [Support Let's Encrypt](#support-lets-encrypt)
    70      - [Run multiple service using Gin](#run-multiple-service-using-gin)
    71      - [Graceful shutdown or restart](#graceful-shutdown-or-restart)
    72        - [Third-party packages](#third-party-packages)
    73        - [Manually](#manually)
    74      - [Build a single binary with templates](#build-a-single-binary-with-templates)
    75      - [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct)
    76      - [Try to bind body into different structs](#try-to-bind-body-into-different-structs)
    77      - [http2 server push](#http2-server-push)
    78      - [Define format for the log of routes](#define-format-for-the-log-of-routes)
    79      - [Set and get a cookie](#set-and-get-a-cookie)
    80    - [Testing](#testing)
    81    - [Users](#users)
    82  
    83  ## Installation
    84  
    85  To install Gin package, you need to install Go and set your Go workspace first.
    86  
    87  1. The first need [Go](https://golang.org/) installed (**version 1.12+ is required**), then you can use the below Go command to install Gin.
    88  
    89  ```sh
    90  $ go get -u github.com/gin-gonic/gin
    91  ```
    92  
    93  2. Import it in your code:
    94  
    95  ```go
    96  import "github.com/hellobchain/third_party/gin"
    97  ```
    98  
    99  3. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`.
   100  
   101  ```go
   102  import "github.com/hellobchain/newcryptosm/http"
   103  ```
   104  
   105  ## Quick start
   106  
   107  ```sh
   108  # assume the following codes in example.go file
   109  $ cat example.go
   110  ```
   111  
   112  ```go
   113  package main
   114  
   115  import "github.com/hellobchain/third_party/gin"
   116  
   117  func main() {
   118  	r := gin.Default()
   119  	r.GET("/ping", func(c *gin.Context) {
   120  		c.JSON(200, gin.H{
   121  			"message": "pong",
   122  		})
   123  	})
   124  	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
   125  }
   126  ```
   127  
   128  ```
   129  # run example.go and visit 0.0.0.0:8080/ping (for windows "localhost:8080/ping") on browser
   130  $ go run example.go
   131  ```
   132  
   133  ## Benchmarks
   134  
   135  Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter)
   136  
   137  [See all benchmarks](/BENCHMARKS.md)
   138  
   139  | Benchmark name                 |       (1) |             (2) |          (3) |             (4) |
   140  | ------------------------------ | ---------:| ---------------:| ------------:| ---------------:|
   141  | BenchmarkGin_GithubAll         | **43550** | **27364 ns/op** |   **0 B/op** | **0 allocs/op** |
   142  | BenchmarkAce_GithubAll         |     40543 |     29670 ns/op |       0 B/op |     0 allocs/op |
   143  | BenchmarkAero_GithubAll        |     57632 |     20648 ns/op |       0 B/op |     0 allocs/op |
   144  | BenchmarkBear_GithubAll        |      9234 |    216179 ns/op |   86448 B/op |   943 allocs/op |
   145  | BenchmarkBeego_GithubAll       |      7407 |    243496 ns/op |   71456 B/op |   609 allocs/op |
   146  | BenchmarkBone_GithubAll        |       420 |   2922835 ns/op |  720160 B/op |  8620 allocs/op |
   147  | BenchmarkChi_GithubAll         |      7620 |    238331 ns/op |   87696 B/op |   609 allocs/op |
   148  | BenchmarkDenco_GithubAll       |     18355 |     64494 ns/op |   20224 B/op |   167 allocs/op |
   149  | BenchmarkEcho_GithubAll        |     31251 |     38479 ns/op |       0 B/op |     0 allocs/op |
   150  | BenchmarkGocraftWeb_GithubAll  |      4117 |    300062 ns/op |  131656 B/op |  1686 allocs/op |
   151  | BenchmarkGoji_GithubAll        |      3274 |    416158 ns/op |   56112 B/op |   334 allocs/op |
   152  | BenchmarkGojiv2_GithubAll      |      1402 |    870518 ns/op |  352720 B/op |  4321 allocs/op |
   153  | BenchmarkGoJsonRest_GithubAll  |      2976 |    401507 ns/op |  134371 B/op |  2737 allocs/op |
   154  | BenchmarkGoRestful_GithubAll   |       410 |   2913158 ns/op |  910144 B/op |  2938 allocs/op |
   155  | BenchmarkGorillaMux_GithubAll  |       346 |   3384987 ns/op |  251650 B/op |  1994 allocs/op |
   156  | BenchmarkGowwwRouter_GithubAll |     10000 |    143025 ns/op |   72144 B/op |   501 allocs/op |
   157  | BenchmarkHttpRouter_GithubAll  |     55938 |     21360 ns/op |       0 B/op |     0 allocs/op |
   158  | BenchmarkHttpTreeMux_GithubAll |     10000 |    153944 ns/op |   65856 B/op |   671 allocs/op |
   159  | BenchmarkKocha_GithubAll       |     10000 |    106315 ns/op |   23304 B/op |   843 allocs/op |
   160  | BenchmarkLARS_GithubAll        |     47779 |     25084 ns/op |       0 B/op |     0 allocs/op |
   161  | BenchmarkMacaron_GithubAll     |      3266 |    371907 ns/op |  149409 B/op |  1624 allocs/op |
   162  | BenchmarkMartini_GithubAll     |       331 |   3444706 ns/op |  226551 B/op |  2325 allocs/op |
   163  | BenchmarkPat_GithubAll         |       273 |   4381818 ns/op | 1483152 B/op | 26963 allocs/op |
   164  | BenchmarkPossum_GithubAll      |     10000 |    164367 ns/op |   84448 B/op |   609 allocs/op |
   165  | BenchmarkR2router_GithubAll    |     10000 |    160220 ns/op |   77328 B/op |   979 allocs/op |
   166  | BenchmarkRivet_GithubAll       |     14625 |     82453 ns/op |   16272 B/op |   167 allocs/op |
   167  | BenchmarkTango_GithubAll       |      6255 |    279611 ns/op |   63826 B/op |  1618 allocs/op |
   168  | BenchmarkTigerTonic_GithubAll  |      2008 |    687874 ns/op |  193856 B/op |  4474 allocs/op |
   169  | BenchmarkTraffic_GithubAll     |       355 |   3478508 ns/op |  820744 B/op | 14114 allocs/op |
   170  | BenchmarkVulcan_GithubAll      |      6885 |    193333 ns/op |   19894 B/op |   609 allocs/op |
   171  
   172  - (1): Total Repetitions achieved in constant time, higher means more confident result
   173  - (2): Single Repetition Duration (ns/op), lower is better
   174  - (3): Heap Memory (B/op), lower is better
   175  - (4): Average Allocations per Repetition (allocs/op), lower is better
   176  
   177  ## Gin v1. stable
   178  
   179  - [x] Zero allocation router.
   180  - [x] Still the fastest http router and framework. From routing to writing.
   181  - [x] Complete suite of unit tests.
   182  - [x] Battle tested.
   183  - [x] API frozen, new releases will not break your code.
   184  
   185  ## Build with [jsoniter](https://github.com/json-iterator/go)
   186  
   187  Gin uses `encoding/json` as default json package but you can change to [jsoniter](https://github.com/json-iterator/go) by build from other tags.
   188  
   189  ```sh
   190  $ go build -tags=jsoniter .
   191  ```
   192  
   193  ## API Examples
   194  
   195  You can find a number of ready-to-run examples at [Gin examples repository](https://github.com/gin-gonic/examples).
   196  
   197  ### Using GET, POST, PUT, PATCH, DELETE and OPTIONS
   198  
   199  ```go
   200  func main() {
   201  	// Creates a gin router with default middleware:
   202  	// logger and recovery (crash-free) middleware
   203  	router := gin.Default()
   204  
   205  	router.GET("/someGet", getting)
   206  	router.POST("/somePost", posting)
   207  	router.PUT("/somePut", putting)
   208  	router.DELETE("/someDelete", deleting)
   209  	router.PATCH("/somePatch", patching)
   210  	router.HEAD("/someHead", head)
   211  	router.OPTIONS("/someOptions", options)
   212  
   213  	// By default it serves on :8080 unless a
   214  	// PORT environment variable was defined.
   215  	router.Run()
   216  	// router.Run(":3000") for a hard coded port
   217  }
   218  ```
   219  
   220  ### Parameters in path
   221  
   222  ```go
   223  func main() {
   224  	router := gin.Default()
   225  
   226  	// This handler will match /user/john but will not match /user/ or /user
   227  	router.GET("/user/:name", func(c *gin.Context) {
   228  		name := c.Param("name")
   229  		c.String(http.StatusOK, "Hello %s", name)
   230  	})
   231  
   232  	// However, this one will match /user/john/ and also /user/john/send
   233  	// If no other routers match /user/john, it will redirect to /user/john/
   234  	router.GET("/user/:name/*action", func(c *gin.Context) {
   235  		name := c.Param("name")
   236  		action := c.Param("action")
   237  		message := name + " is " + action
   238  		c.String(http.StatusOK, message)
   239  	})
   240  
   241  	// For each matched request Context will hold the route definition
   242  	router.POST("/user/:name/*action", func(c *gin.Context) {
   243  		c.FullPath() == "/user/:name/*action" // true
   244  	})
   245  
   246  	// This handler will add a new router for /user/groups.
   247  	// Exact routes are resolved before param routes, regardless of the order they were defined.
   248  	// Routes starting with /user/groups are never interpreted as /user/:name/... routes
   249  	router.GET("/user/groups", func(c *gin.Context) {
   250  		c.String(http.StatusOK, "The available groups are [...]", name)
   251  	})
   252  
   253  	router.Run(":8080")
   254  }
   255  ```
   256  
   257  ### Querystring parameters
   258  
   259  ```go
   260  func main() {
   261  	router := gin.Default()
   262  
   263  	// Query string parameters are parsed using the existing underlying request object.
   264  	// The request responds to a url matching:  /welcome?firstname=Jane&lastname=Doe
   265  	router.GET("/welcome", func(c *gin.Context) {
   266  		firstname := c.DefaultQuery("firstname", "Guest")
   267  		lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")
   268  
   269  		c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
   270  	})
   271  	router.Run(":8080")
   272  }
   273  ```
   274  
   275  ### Multipart/Urlencoded Form
   276  
   277  ```go
   278  func main() {
   279  	router := gin.Default()
   280  
   281  	router.POST("/form_post", func(c *gin.Context) {
   282  		message := c.PostForm("message")
   283  		nick := c.DefaultPostForm("nick", "anonymous")
   284  
   285  		c.JSON(200, gin.H{
   286  			"status":  "posted",
   287  			"message": message,
   288  			"nick":    nick,
   289  		})
   290  	})
   291  	router.Run(":8080")
   292  }
   293  ```
   294  
   295  ### Another example: query + post form
   296  
   297  ```
   298  POST /post?id=1234&page=1 HTTP/1.1
   299  Content-Type: application/x-www-form-urlencoded
   300  
   301  name=manu&message=this_is_great
   302  ```
   303  
   304  ```go
   305  func main() {
   306  	router := gin.Default()
   307  
   308  	router.POST("/post", func(c *gin.Context) {
   309  
   310  		id := c.Query("id")
   311  		page := c.DefaultQuery("page", "0")
   312  		name := c.PostForm("name")
   313  		message := c.PostForm("message")
   314  
   315  		fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
   316  	})
   317  	router.Run(":8080")
   318  }
   319  ```
   320  
   321  ```
   322  id: 1234; page: 1; name: manu; message: this_is_great
   323  ```
   324  
   325  ### Map as querystring or postform parameters
   326  
   327  ```
   328  POST /post?ids[a]=1234&ids[b]=hello HTTP/1.1
   329  Content-Type: application/x-www-form-urlencoded
   330  
   331  names[first]=thinkerou&names[second]=tianou
   332  ```
   333  
   334  ```go
   335  func main() {
   336  	router := gin.Default()
   337  
   338  	router.POST("/post", func(c *gin.Context) {
   339  
   340  		ids := c.QueryMap("ids")
   341  		names := c.PostFormMap("names")
   342  
   343  		fmt.Printf("ids: %v; names: %v", ids, names)
   344  	})
   345  	router.Run(":8080")
   346  }
   347  ```
   348  
   349  ```
   350  ids: map[b:hello a:1234]; names: map[second:tianou first:thinkerou]
   351  ```
   352  
   353  ### Upload files
   354  
   355  #### Single file
   356  
   357  References issue [#774](https://github.com/gin-gonic/gin/issues/774) and detail [example code](https://github.com/gin-gonic/examples/tree/master/upload-file/single).
   358  
   359  `file.Filename` **SHOULD NOT** be trusted. See [`Content-Disposition` on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#Directives) and [#1693](https://github.com/gin-gonic/gin/issues/1693)
   360  
   361  > The filename is always optional and must not be used blindly by the application: path information should be stripped, and conversion to the server file system rules should be done.
   362  
   363  ```go
   364  func main() {
   365  	router := gin.Default()
   366  	// Set a lower memory limit for multipart forms (default is 32 MiB)
   367  	router.MaxMultipartMemory = 8 << 20  // 8 MiB
   368  	router.POST("/upload", func(c *gin.Context) {
   369  		// single file
   370  		file, _ := c.FormFile("file")
   371  		log.Println(file.Filename)
   372  
   373  		// Upload the file to specific dst.
   374  		c.SaveUploadedFile(file, dst)
   375  
   376  		c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
   377  	})
   378  	router.Run(":8080")
   379  }
   380  ```
   381  
   382  How to `curl`:
   383  
   384  ```bash
   385  curl -X POST http://localhost:8080/upload \
   386    -F "file=@/Users/appleboy/test.zip" \
   387    -H "Content-Type: multipart/form-data"
   388  ```
   389  
   390  #### Multiple files
   391  
   392  See the detail [example code](https://github.com/gin-gonic/examples/tree/master/upload-file/multiple).
   393  
   394  ```go
   395  func main() {
   396  	router := gin.Default()
   397  	// Set a lower memory limit for multipart forms (default is 32 MiB)
   398  	router.MaxMultipartMemory = 8 << 20  // 8 MiB
   399  	router.POST("/upload", func(c *gin.Context) {
   400  		// Multipart form
   401  		form, _ := c.MultipartForm()
   402  		files := form.File["upload[]"]
   403  
   404  		for _, file := range files {
   405  			log.Println(file.Filename)
   406  
   407  			// Upload the file to specific dst.
   408  			c.SaveUploadedFile(file, dst)
   409  		}
   410  		c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
   411  	})
   412  	router.Run(":8080")
   413  }
   414  ```
   415  
   416  How to `curl`:
   417  
   418  ```bash
   419  curl -X POST http://localhost:8080/upload \
   420    -F "upload[]=@/Users/appleboy/test1.zip" \
   421    -F "upload[]=@/Users/appleboy/test2.zip" \
   422    -H "Content-Type: multipart/form-data"
   423  ```
   424  
   425  ### Grouping routes
   426  
   427  ```go
   428  func main() {
   429  	router := gin.Default()
   430  
   431  	// Simple group: v1
   432  	v1 := router.Group("/v1")
   433  	{
   434  		v1.POST("/login", loginEndpoint)
   435  		v1.POST("/submit", submitEndpoint)
   436  		v1.POST("/read", readEndpoint)
   437  	}
   438  
   439  	// Simple group: v2
   440  	v2 := router.Group("/v2")
   441  	{
   442  		v2.POST("/login", loginEndpoint)
   443  		v2.POST("/submit", submitEndpoint)
   444  		v2.POST("/read", readEndpoint)
   445  	}
   446  
   447  	router.Run(":8080")
   448  }
   449  ```
   450  
   451  ### Blank Gin without middleware by default
   452  
   453  Use
   454  
   455  ```go
   456  r := gin.New()
   457  ```
   458  
   459  instead of
   460  
   461  ```go
   462  // Default With the Logger and Recovery middleware already attached
   463  r := gin.Default()
   464  ```
   465  
   466  
   467  ### Using middleware
   468  ```go
   469  func main() {
   470  	// Creates a router without any middleware by default
   471  	r := gin.New()
   472  
   473  	// Global middleware
   474  	// Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release.
   475  	// By default gin.DefaultWriter = os.Stdout
   476  	r.Use(gin.Logger())
   477  
   478  	// Recovery middleware recovers from any panics and writes a 500 if there was one.
   479  	r.Use(gin.Recovery())
   480  
   481  	// Per route middleware, you can add as many as you desire.
   482  	r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
   483  
   484  	// Authorization group
   485  	// authorized := r.Group("/", AuthRequired())
   486  	// exactly the same as:
   487  	authorized := r.Group("/")
   488  	// per group middleware! in this case we use the custom created
   489  	// AuthRequired() middleware just in the "authorized" group.
   490  	authorized.Use(AuthRequired())
   491  	{
   492  		authorized.POST("/login", loginEndpoint)
   493  		authorized.POST("/submit", submitEndpoint)
   494  		authorized.POST("/read", readEndpoint)
   495  
   496  		// nested group
   497  		testing := authorized.Group("testing")
   498  		testing.GET("/analytics", analyticsEndpoint)
   499  	}
   500  
   501  	// Listen and serve on 0.0.0.0:8080
   502  	r.Run(":8080")
   503  }
   504  ```
   505  
   506  ### Custom Recovery behavior
   507  ```go
   508  func main() {
   509  	// Creates a router without any middleware by default
   510  	r := gin.New()
   511  
   512  	// Global middleware
   513  	// Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release.
   514  	// By default gin.DefaultWriter = os.Stdout
   515  	r.Use(gin.Logger())
   516  
   517  	// Recovery middleware recovers from any panics and writes a 500 if there was one.
   518  	r.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
   519  		if err, ok := recovered.(string); ok {
   520  			c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
   521  		}
   522  		c.AbortWithStatus(http.StatusInternalServerError)
   523  	}))
   524  
   525  	r.GET("/panic", func(c *gin.Context) {
   526  		// panic with a string -- the custom middleware could save this to a database or report it to the user
   527  		panic("foo")
   528  	})
   529  
   530  	r.GET("/", func(c *gin.Context) {
   531  		c.String(http.StatusOK, "ohai")
   532  	})
   533  
   534  	// Listen and serve on 0.0.0.0:8080
   535  	r.Run(":8080")
   536  }
   537  ```
   538  
   539  ### How to write log file
   540  ```go
   541  func main() {
   542      // Disable Console Color, you don't need console color when writing the logs to file.
   543      gin.DisableConsoleColor()
   544  
   545      // Logging to a file.
   546      f, _ := os.Create("gin.log")
   547      gin.DefaultWriter = io.MultiWriter(f)
   548  
   549      // Use the following code if you need to write the logs to file and console at the same time.
   550      // gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
   551  
   552      router := gin.Default()
   553      router.GET("/ping", func(c *gin.Context) {
   554          c.String(200, "pong")
   555      })
   556  
   557      router.Run(":8080")
   558  }
   559  ```
   560  
   561  ### Custom Log Format
   562  ```go
   563  func main() {
   564  	router := gin.New()
   565  
   566  	// LoggerWithFormatter middleware will write the logs to gin.DefaultWriter
   567  	// By default gin.DefaultWriter = os.Stdout
   568  	router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
   569  
   570  		// your custom format
   571  		return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
   572  				param.ClientIP,
   573  				param.TimeStamp.Format(time.RFC1123),
   574  				param.Method,
   575  				param.Path,
   576  				param.Request.Proto,
   577  				param.StatusCode,
   578  				param.Latency,
   579  				param.Request.UserAgent(),
   580  				param.ErrorMessage,
   581  		)
   582  	}))
   583  	router.Use(gin.Recovery())
   584  
   585  	router.GET("/ping", func(c *gin.Context) {
   586  		c.String(200, "pong")
   587  	})
   588  
   589  	router.Run(":8080")
   590  }
   591  ```
   592  
   593  **Sample Output**
   594  ```
   595  ::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" "
   596  ```
   597  
   598  ### Controlling Log output coloring
   599  
   600  By default, logs output on console should be colorized depending on the detected TTY.
   601  
   602  Never colorize logs:
   603  
   604  ```go
   605  func main() {
   606      // Disable log's color
   607      gin.DisableConsoleColor()
   608  
   609      // Creates a gin router with default middleware:
   610      // logger and recovery (crash-free) middleware
   611      router := gin.Default()
   612  
   613      router.GET("/ping", func(c *gin.Context) {
   614          c.String(200, "pong")
   615      })
   616  
   617      router.Run(":8080")
   618  }
   619  ```
   620  
   621  Always colorize logs:
   622  
   623  ```go
   624  func main() {
   625      // Force log's color
   626      gin.ForceConsoleColor()
   627  
   628      // Creates a gin router with default middleware:
   629      // logger and recovery (crash-free) middleware
   630      router := gin.Default()
   631  
   632      router.GET("/ping", func(c *gin.Context) {
   633          c.String(200, "pong")
   634      })
   635  
   636      router.Run(":8080")
   637  }
   638  ```
   639  
   640  ### Model binding and validation
   641  
   642  To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML and standard form values (foo=bar&boo=baz).
   643  
   644  Gin uses [**go-playground/validator/v10**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](https://godoc.org/github.com/go-playground/validator#hdr-Baked_In_Validators_and_Tags).
   645  
   646  Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`.
   647  
   648  Also, Gin provides two sets of methods for binding:
   649  - **Type** - Must bind
   650    - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML`, `BindHeader`
   651    - **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method.
   652  - **Type** - Should bind
   653    - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML`, `ShouldBindHeader`
   654    - **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately.
   655  
   656  When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`.
   657  
   658  You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has a empty value when binding, an error will be returned.
   659  
   660  ```go
   661  // Binding from JSON
   662  type Login struct {
   663  	User     string `form:"user" json:"user" xml:"user"  binding:"required"`
   664  	Password string `form:"password" json:"password" xml:"password" binding:"required"`
   665  }
   666  
   667  func main() {
   668  	router := gin.Default()
   669  
   670  	// Example for binding JSON ({"user": "manu", "password": "123"})
   671  	router.POST("/loginJSON", func(c *gin.Context) {
   672  		var json Login
   673  		if err := c.ShouldBindJSON(&json); err != nil {
   674  			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
   675  			return
   676  		}
   677  
   678  		if json.User != "manu" || json.Password != "123" {
   679  			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
   680  			return
   681  		}
   682  
   683  		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
   684  	})
   685  
   686  	// Example for binding XML (
   687  	//	<?xml version="1.0" encoding="UTF-8"?>
   688  	//	<root>
   689  	//		<user>user</user>
   690  	//		<password>123</password>
   691  	//	</root>)
   692  	router.POST("/loginXML", func(c *gin.Context) {
   693  		var xml Login
   694  		if err := c.ShouldBindXML(&xml); err != nil {
   695  			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
   696  			return
   697  		}
   698  
   699  		if xml.User != "manu" || xml.Password != "123" {
   700  			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
   701  			return
   702  		}
   703  
   704  		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
   705  	})
   706  
   707  	// Example for binding a HTML form (user=manu&password=123)
   708  	router.POST("/loginForm", func(c *gin.Context) {
   709  		var form Login
   710  		// This will infer what binder to use depending on the content-type header.
   711  		if err := c.ShouldBind(&form); err != nil {
   712  			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
   713  			return
   714  		}
   715  
   716  		if form.User != "manu" || form.Password != "123" {
   717  			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
   718  			return
   719  		}
   720  
   721  		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
   722  	})
   723  
   724  	// Listen and serve on 0.0.0.0:8080
   725  	router.Run(":8080")
   726  }
   727  ```
   728  
   729  **Sample request**
   730  ```shell
   731  $ curl -v -X POST \
   732    http://localhost:8080/loginJSON \
   733    -H 'content-type: application/json' \
   734    -d '{ "user": "manu" }'
   735  > POST /loginJSON HTTP/1.1
   736  > Host: localhost:8080
   737  > User-Agent: curl/7.51.0
   738  > Accept: */*
   739  > content-type: application/json
   740  > Content-Length: 18
   741  >
   742  * upload completely sent off: 18 out of 18 bytes
   743  < HTTP/1.1 400 Bad Request
   744  < Content-Type: application/json; charset=utf-8
   745  < Date: Fri, 04 Aug 2017 03:51:31 GMT
   746  < Content-Length: 100
   747  <
   748  {"error":"Key: 'Login.Password' Error:Field validation for 'Password' failed on the 'required' tag"}
   749  ```
   750  
   751  **Skip validate**
   752  
   753  When running the above example using the above the `curl` command, it returns error. Because the example use `binding:"required"` for `Password`. If use `binding:"-"` for `Password`, then it will not return error when running the above example again.
   754  
   755  ### Custom Validators
   756  
   757  It is also possible to register custom validators. See the [example code](https://github.com/gin-gonic/examples/tree/master/custom-validation/server.go).
   758  
   759  ```go
   760  package main
   761  
   762  import (
   763  	"github.com/hellobchain/newcryptosm/http"
   764  	"time"
   765  
   766  	"github.com/hellobchain/third_party/gin"
   767  	"github.com/hellobchain/third_party/gin/binding"
   768  	"github.com/go-playground/validator/v10"
   769  )
   770  
   771  // Booking contains binded and validated data.
   772  type Booking struct {
   773  	CheckIn  time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
   774  	CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`
   775  }
   776  
   777  var bookableDate validator.Func = func(fl validator.FieldLevel) bool {
   778  	date, ok := fl.Field().Interface().(time.Time)
   779  	if ok {
   780  		today := time.Now()
   781  		if today.After(date) {
   782  			return false
   783  		}
   784  	}
   785  	return true
   786  }
   787  
   788  func main() {
   789  	route := gin.Default()
   790  
   791  	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
   792  		v.RegisterValidation("bookabledate", bookableDate)
   793  	}
   794  
   795  	route.GET("/bookable", getBookable)
   796  	route.Run(":8085")
   797  }
   798  
   799  func getBookable(c *gin.Context) {
   800  	var b Booking
   801  	if err := c.ShouldBindWith(&b, binding.Query); err == nil {
   802  		c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})
   803  	} else {
   804  		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
   805  	}
   806  }
   807  ```
   808  
   809  ```console
   810  $ curl "localhost:8085/bookable?check_in=2030-04-16&check_out=2030-04-17"
   811  {"message":"Booking dates are valid!"}
   812  
   813  $ curl "localhost:8085/bookable?check_in=2030-03-10&check_out=2030-03-09"
   814  {"error":"Key: 'Booking.CheckOut' Error:Field validation for 'CheckOut' failed on the 'gtfield' tag"}
   815  
   816  $ curl "localhost:8085/bookable?check_in=2000-03-09&check_out=2000-03-10"
   817  {"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"}%
   818  ```
   819  
   820  [Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registered this way.
   821  See the [struct-lvl-validation example](https://github.com/gin-gonic/examples/tree/master/struct-lvl-validations) to learn more.
   822  
   823  ### Only Bind Query String
   824  
   825  `ShouldBindQuery` function only binds the query params and not the post data. See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-315953017).
   826  
   827  ```go
   828  package main
   829  
   830  import (
   831  	"log"
   832  
   833  	"github.com/hellobchain/third_party/gin"
   834  )
   835  
   836  type Person struct {
   837  	Name    string `form:"name"`
   838  	Address string `form:"address"`
   839  }
   840  
   841  func main() {
   842  	route := gin.Default()
   843  	route.Any("/testing", startPage)
   844  	route.Run(":8085")
   845  }
   846  
   847  func startPage(c *gin.Context) {
   848  	var person Person
   849  	if c.ShouldBindQuery(&person) == nil {
   850  		log.Println("====== Only Bind By Query String ======")
   851  		log.Println(person.Name)
   852  		log.Println(person.Address)
   853  	}
   854  	c.String(200, "Success")
   855  }
   856  
   857  ```
   858  
   859  ### Bind Query String or Post Data
   860  
   861  See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292).
   862  
   863  ```go
   864  package main
   865  
   866  import (
   867  	"log"
   868  	"time"
   869  
   870  	"github.com/hellobchain/third_party/gin"
   871  )
   872  
   873  type Person struct {
   874          Name       string    `form:"name"`
   875          Address    string    `form:"address"`
   876          Birthday   time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
   877          CreateTime time.Time `form:"createTime" time_format:"unixNano"`
   878          UnixTime   time.Time `form:"unixTime" time_format:"unix"`
   879  }
   880  
   881  func main() {
   882  	route := gin.Default()
   883  	route.GET("/testing", startPage)
   884  	route.Run(":8085")
   885  }
   886  
   887  func startPage(c *gin.Context) {
   888  	var person Person
   889  	// If `GET`, only `Form` binding engine (`query`) used.
   890  	// If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).
   891  	// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48
   892          if c.ShouldBind(&person) == nil {
   893                  log.Println(person.Name)
   894                  log.Println(person.Address)
   895                  log.Println(person.Birthday)
   896                  log.Println(person.CreateTime)
   897                  log.Println(person.UnixTime)
   898          }
   899  
   900  	c.String(200, "Success")
   901  }
   902  ```
   903  
   904  Test it with:
   905  ```sh
   906  $ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
   907  ```
   908  
   909  ### Bind Uri
   910  
   911  See the [detail information](https://github.com/gin-gonic/gin/issues/846).
   912  
   913  ```go
   914  package main
   915  
   916  import "github.com/hellobchain/third_party/gin"
   917  
   918  type Person struct {
   919  	ID string `uri:"id" binding:"required,uuid"`
   920  	Name string `uri:"name" binding:"required"`
   921  }
   922  
   923  func main() {
   924  	route := gin.Default()
   925  	route.GET("/:name/:id", func(c *gin.Context) {
   926  		var person Person
   927  		if err := c.ShouldBindUri(&person); err != nil {
   928  			c.JSON(400, gin.H{"msg": err})
   929  			return
   930  		}
   931  		c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID})
   932  	})
   933  	route.Run(":8088")
   934  }
   935  ```
   936  
   937  Test it with:
   938  ```sh
   939  $ curl -v localhost:8088/thinkerou/987fbc97-4bed-5078-9f07-9141ba07c9f3
   940  $ curl -v localhost:8088/thinkerou/not-uuid
   941  ```
   942  
   943  ### Bind Header
   944  
   945  ```go
   946  package main
   947  
   948  import (
   949  	"fmt"
   950  	"github.com/hellobchain/third_party/gin"
   951  )
   952  
   953  type testHeader struct {
   954  	Rate   int    `header:"Rate"`
   955  	Domain string `header:"Domain"`
   956  }
   957  
   958  func main() {
   959  	r := gin.Default()
   960  	r.GET("/", func(c *gin.Context) {
   961  		h := testHeader{}
   962  
   963  		if err := c.ShouldBindHeader(&h); err != nil {
   964  			c.JSON(200, err)
   965  		}
   966  
   967  		fmt.Printf("%#v\n", h)
   968  		c.JSON(200, gin.H{"Rate": h.Rate, "Domain": h.Domain})
   969  	})
   970  
   971  	r.Run()
   972  
   973  // client
   974  // curl -H "rate:300" -H "domain:music" 127.0.0.1:8080/
   975  // output
   976  // {"Domain":"music","Rate":300}
   977  }
   978  ```
   979  
   980  ### Bind HTML checkboxes
   981  
   982  See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092)
   983  
   984  main.go
   985  
   986  ```go
   987  ...
   988  
   989  type myForm struct {
   990      Colors []string `form:"colors[]"`
   991  }
   992  
   993  ...
   994  
   995  func formHandler(c *gin.Context) {
   996      var fakeForm myForm
   997      c.ShouldBind(&fakeForm)
   998      c.JSON(200, gin.H{"color": fakeForm.Colors})
   999  }
  1000  
  1001  ...
  1002  
  1003  ```
  1004  
  1005  form.html
  1006  
  1007  ```html
  1008  <form action="/" method="POST">
  1009      <p>Check some colors</p>
  1010      <label for="red">Red</label>
  1011      <input type="checkbox" name="colors[]" value="red" id="red">
  1012      <label for="green">Green</label>
  1013      <input type="checkbox" name="colors[]" value="green" id="green">
  1014      <label for="blue">Blue</label>
  1015      <input type="checkbox" name="colors[]" value="blue" id="blue">
  1016      <input type="submit">
  1017  </form>
  1018  ```
  1019  
  1020  result:
  1021  
  1022  ```
  1023  {"color":["red","green","blue"]}
  1024  ```
  1025  
  1026  ### Multipart/Urlencoded binding
  1027  
  1028  ```go
  1029  type ProfileForm struct {
  1030  	Name   string                `form:"name" binding:"required"`
  1031  	Avatar *multipart.FileHeader `form:"avatar" binding:"required"`
  1032  
  1033  	// or for multiple files
  1034  	// Avatars []*multipart.FileHeader `form:"avatar" binding:"required"`
  1035  }
  1036  
  1037  func main() {
  1038  	router := gin.Default()
  1039  	router.POST("/profile", func(c *gin.Context) {
  1040  		// you can bind multipart form with explicit binding declaration:
  1041  		// c.ShouldBindWith(&form, binding.Form)
  1042  		// or you can simply use autobinding with ShouldBind method:
  1043  		var form ProfileForm
  1044  		// in this case proper binding will be automatically selected
  1045  		if err := c.ShouldBind(&form); err != nil {
  1046  			c.String(http.StatusBadRequest, "bad request")
  1047  			return
  1048  		}
  1049  
  1050  		err := c.SaveUploadedFile(form.Avatar, form.Avatar.Filename)
  1051  		if err != nil {
  1052  			c.String(http.StatusInternalServerError, "unknown error")
  1053  			return
  1054  		}
  1055  
  1056  		// db.Save(&form)
  1057  
  1058  		c.String(http.StatusOK, "ok")
  1059  	})
  1060  	router.Run(":8080")
  1061  }
  1062  ```
  1063  
  1064  Test it with:
  1065  ```sh
  1066  $ curl -X POST -v --form name=user --form "avatar=@./avatar.png" http://localhost:8080/profile
  1067  ```
  1068  
  1069  ### XML, JSON, YAML and ProtoBuf rendering
  1070  
  1071  ```go
  1072  func main() {
  1073  	r := gin.Default()
  1074  
  1075  	// gin.H is a shortcut for map[string]interface{}
  1076  	r.GET("/someJSON", func(c *gin.Context) {
  1077  		c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
  1078  	})
  1079  
  1080  	r.GET("/moreJSON", func(c *gin.Context) {
  1081  		// You also can use a struct
  1082  		var msg struct {
  1083  			Name    string `json:"user"`
  1084  			Message string
  1085  			Number  int
  1086  		}
  1087  		msg.Name = "Lena"
  1088  		msg.Message = "hey"
  1089  		msg.Number = 123
  1090  		// Note that msg.Name becomes "user" in the JSON
  1091  		// Will output  :   {"user": "Lena", "Message": "hey", "Number": 123}
  1092  		c.JSON(http.StatusOK, msg)
  1093  	})
  1094  
  1095  	r.GET("/someXML", func(c *gin.Context) {
  1096  		c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
  1097  	})
  1098  
  1099  	r.GET("/someYAML", func(c *gin.Context) {
  1100  		c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
  1101  	})
  1102  
  1103  	r.GET("/someProtoBuf", func(c *gin.Context) {
  1104  		reps := []int64{int64(1), int64(2)}
  1105  		label := "test"
  1106  		// The specific definition of protobuf is written in the testdata/protoexample file.
  1107  		data := &protoexample.Test{
  1108  			Label: &label,
  1109  			Reps:  reps,
  1110  		}
  1111  		// Note that data becomes binary data in the response
  1112  		// Will output protoexample.Test protobuf serialized data
  1113  		c.ProtoBuf(http.StatusOK, data)
  1114  	})
  1115  
  1116  	// Listen and serve on 0.0.0.0:8080
  1117  	r.Run(":8080")
  1118  }
  1119  ```
  1120  
  1121  #### SecureJSON
  1122  
  1123  Using SecureJSON to prevent json hijacking. Default prepends `"while(1),"` to response body if the given struct is array values.
  1124  
  1125  ```go
  1126  func main() {
  1127  	r := gin.Default()
  1128  
  1129  	// You can also use your own secure json prefix
  1130  	// r.SecureJsonPrefix(")]}',\n")
  1131  
  1132  	r.GET("/someJSON", func(c *gin.Context) {
  1133  		names := []string{"lena", "austin", "foo"}
  1134  
  1135  		// Will output  :   while(1);["lena","austin","foo"]
  1136  		c.SecureJSON(http.StatusOK, names)
  1137  	})
  1138  
  1139  	// Listen and serve on 0.0.0.0:8080
  1140  	r.Run(":8080")
  1141  }
  1142  ```
  1143  #### JSONP
  1144  
  1145  Using JSONP to request data from a server  in a different domain. Add callback to response body if the query parameter callback exists.
  1146  
  1147  ```go
  1148  func main() {
  1149  	r := gin.Default()
  1150  
  1151  	r.GET("/JSONP", func(c *gin.Context) {
  1152  		data := gin.H{
  1153  			"foo": "bar",
  1154  		}
  1155  
  1156  		//callback is x
  1157  		// Will output  :   x({\"foo\":\"bar\"})
  1158  		c.JSONP(http.StatusOK, data)
  1159  	})
  1160  
  1161  	// Listen and serve on 0.0.0.0:8080
  1162  	r.Run(":8080")
  1163  
  1164          // client
  1165          // curl http://127.0.0.1:8080/JSONP?callback=x
  1166  }
  1167  ```
  1168  
  1169  #### AsciiJSON
  1170  
  1171  Using AsciiJSON to Generates ASCII-only JSON with escaped non-ASCII characters.
  1172  
  1173  ```go
  1174  func main() {
  1175  	r := gin.Default()
  1176  
  1177  	r.GET("/someJSON", func(c *gin.Context) {
  1178  		data := gin.H{
  1179  			"lang": "GO语言",
  1180  			"tag":  "<br>",
  1181  		}
  1182  
  1183  		// will output : {"lang":"GO\u8bed\u8a00","tag":"\u003cbr\u003e"}
  1184  		c.AsciiJSON(http.StatusOK, data)
  1185  	})
  1186  
  1187  	// Listen and serve on 0.0.0.0:8080
  1188  	r.Run(":8080")
  1189  }
  1190  ```
  1191  
  1192  #### PureJSON
  1193  
  1194  Normally, JSON replaces special HTML characters with their unicode entities, e.g. `<` becomes  `\u003c`. If you want to encode such characters literally, you can use PureJSON instead.
  1195  This feature is unavailable in Go 1.6 and lower.
  1196  
  1197  ```go
  1198  func main() {
  1199  	r := gin.Default()
  1200  
  1201  	// Serves unicode entities
  1202  	r.GET("/json", func(c *gin.Context) {
  1203  		c.JSON(200, gin.H{
  1204  			"html": "<b>Hello, world!</b>",
  1205  		})
  1206  	})
  1207  
  1208  	// Serves literal characters
  1209  	r.GET("/purejson", func(c *gin.Context) {
  1210  		c.PureJSON(200, gin.H{
  1211  			"html": "<b>Hello, world!</b>",
  1212  		})
  1213  	})
  1214  
  1215  	// listen and serve on 0.0.0.0:8080
  1216  	r.Run(":8080")
  1217  }
  1218  ```
  1219  
  1220  ### Serving static files
  1221  
  1222  ```go
  1223  func main() {
  1224  	router := gin.Default()
  1225  	router.Static("/assets", "./assets")
  1226  	router.StaticFS("/more_static", http.Dir("my_file_system"))
  1227  	router.StaticFile("/favicon.ico", "./resources/favicon.ico")
  1228  
  1229  	// Listen and serve on 0.0.0.0:8080
  1230  	router.Run(":8080")
  1231  }
  1232  ```
  1233  
  1234  ### Serving data from file
  1235  
  1236  ```go
  1237  func main() {
  1238  	router := gin.Default()
  1239  
  1240  	router.GET("/local/file", func(c *gin.Context) {
  1241  		c.File("local/file.go")
  1242  	})
  1243  
  1244  	var fs http.FileSystem = // ...
  1245  	router.GET("/fs/file", func(c *gin.Context) {
  1246  		c.FileFromFS("fs/file.go", fs)
  1247  	})
  1248  }
  1249  
  1250  ```
  1251  
  1252  ### Serving data from reader
  1253  
  1254  ```go
  1255  func main() {
  1256  	router := gin.Default()
  1257  	router.GET("/someDataFromReader", func(c *gin.Context) {
  1258  		response, err := http.Get("https://raw.githubusercontent.com/gin-gonic/logo/master/color.png")
  1259  		if err != nil || response.StatusCode != http.StatusOK {
  1260  			c.Status(http.StatusServiceUnavailable)
  1261  			return
  1262  		}
  1263  
  1264  		reader := response.Body
  1265   		defer reader.Close()
  1266  		contentLength := response.ContentLength
  1267  		contentType := response.Header.Get("Content-Type")
  1268  
  1269  		extraHeaders := map[string]string{
  1270  			"Content-Disposition": `attachment; filename="gopher.png"`,
  1271  		}
  1272  
  1273  		c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
  1274  	})
  1275  	router.Run(":8080")
  1276  }
  1277  ```
  1278  
  1279  ### HTML rendering
  1280  
  1281  Using LoadHTMLGlob() or LoadHTMLFiles()
  1282  
  1283  ```go
  1284  func main() {
  1285  	router := gin.Default()
  1286  	router.LoadHTMLGlob("templates/*")
  1287  	//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
  1288  	router.GET("/index", func(c *gin.Context) {
  1289  		c.HTML(http.StatusOK, "index.tmpl", gin.H{
  1290  			"title": "Main website",
  1291  		})
  1292  	})
  1293  	router.Run(":8080")
  1294  }
  1295  ```
  1296  
  1297  templates/index.tmpl
  1298  
  1299  ```html
  1300  <html>
  1301  	<h1>
  1302  		{{ .title }}
  1303  	</h1>
  1304  </html>
  1305  ```
  1306  
  1307  Using templates with same name in different directories
  1308  
  1309  ```go
  1310  func main() {
  1311  	router := gin.Default()
  1312  	router.LoadHTMLGlob("templates/**/*")
  1313  	router.GET("/posts/index", func(c *gin.Context) {
  1314  		c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
  1315  			"title": "Posts",
  1316  		})
  1317  	})
  1318  	router.GET("/users/index", func(c *gin.Context) {
  1319  		c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
  1320  			"title": "Users",
  1321  		})
  1322  	})
  1323  	router.Run(":8080")
  1324  }
  1325  ```
  1326  
  1327  templates/posts/index.tmpl
  1328  
  1329  ```html
  1330  {{ define "posts/index.tmpl" }}
  1331  <html><h1>
  1332  	{{ .title }}
  1333  </h1>
  1334  <p>Using posts/index.tmpl</p>
  1335  </html>
  1336  {{ end }}
  1337  ```
  1338  
  1339  templates/users/index.tmpl
  1340  
  1341  ```html
  1342  {{ define "users/index.tmpl" }}
  1343  <html><h1>
  1344  	{{ .title }}
  1345  </h1>
  1346  <p>Using users/index.tmpl</p>
  1347  </html>
  1348  {{ end }}
  1349  ```
  1350  
  1351  #### Custom Template renderer
  1352  
  1353  You can also use your own html template render
  1354  
  1355  ```go
  1356  import "html/template"
  1357  
  1358  func main() {
  1359  	router := gin.Default()
  1360  	html := template.Must(template.ParseFiles("file1", "file2"))
  1361  	router.SetHTMLTemplate(html)
  1362  	router.Run(":8080")
  1363  }
  1364  ```
  1365  
  1366  #### Custom Delimiters
  1367  
  1368  You may use custom delims
  1369  
  1370  ```go
  1371  	r := gin.Default()
  1372  	r.Delims("{[{", "}]}")
  1373  	r.LoadHTMLGlob("/path/to/templates")
  1374  ```
  1375  
  1376  #### Custom Template Funcs
  1377  
  1378  See the detail [example code](https://github.com/gin-gonic/examples/tree/master/template).
  1379  
  1380  main.go
  1381  
  1382  ```go
  1383  import (
  1384      "fmt"
  1385      "html/template"
  1386      "github.com/hellobchain/newcryptosm/http"
  1387      "time"
  1388  
  1389      "github.com/hellobchain/third_party/gin"
  1390  )
  1391  
  1392  func formatAsDate(t time.Time) string {
  1393      year, month, day := t.Date()
  1394      return fmt.Sprintf("%d%02d/%02d", year, month, day)
  1395  }
  1396  
  1397  func main() {
  1398      router := gin.Default()
  1399      router.Delims("{[{", "}]}")
  1400      router.SetFuncMap(template.FuncMap{
  1401          "formatAsDate": formatAsDate,
  1402      })
  1403      router.LoadHTMLFiles("./testdata/template/raw.tmpl")
  1404  
  1405      router.GET("/raw", func(c *gin.Context) {
  1406          c.HTML(http.StatusOK, "raw.tmpl", gin.H{
  1407              "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
  1408          })
  1409      })
  1410  
  1411      router.Run(":8080")
  1412  }
  1413  
  1414  ```
  1415  
  1416  raw.tmpl
  1417  
  1418  ```html
  1419  Date: {[{.now | formatAsDate}]}
  1420  ```
  1421  
  1422  Result:
  1423  ```
  1424  Date: 2017/07/01
  1425  ```
  1426  
  1427  ### Multitemplate
  1428  
  1429  Gin allow by default use only one html.Template. Check [a multitemplate render](https://github.com/gin-contrib/multitemplate) for using features like go 1.6 `block template`.
  1430  
  1431  ### Redirects
  1432  
  1433  Issuing a HTTP redirect is easy. Both internal and external locations are supported.
  1434  
  1435  ```go
  1436  r.GET("/test", func(c *gin.Context) {
  1437  	c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
  1438  })
  1439  ```
  1440  
  1441  Issuing a HTTP redirect from POST. Refer to issue: [#444](https://github.com/gin-gonic/gin/issues/444)
  1442  ```go
  1443  r.POST("/test", func(c *gin.Context) {
  1444  	c.Redirect(http.StatusFound, "/foo")
  1445  })
  1446  ```
  1447  
  1448  Issuing a Router redirect, use `HandleContext` like below.
  1449  
  1450  ``` go
  1451  r.GET("/test", func(c *gin.Context) {
  1452      c.Request.URL.Path = "/test2"
  1453      r.HandleContext(c)
  1454  })
  1455  r.GET("/test2", func(c *gin.Context) {
  1456      c.JSON(200, gin.H{"hello": "world"})
  1457  })
  1458  ```
  1459  
  1460  
  1461  ### Custom Middleware
  1462  
  1463  ```go
  1464  func Logger() gin.HandlerFunc {
  1465  	return func(c *gin.Context) {
  1466  		t := time.Now()
  1467  
  1468  		// Set example variable
  1469  		c.Set("example", "12345")
  1470  
  1471  		// before request
  1472  
  1473  		c.Next()
  1474  
  1475  		// after request
  1476  		latency := time.Since(t)
  1477  		log.Print(latency)
  1478  
  1479  		// access the status we are sending
  1480  		status := c.Writer.Status()
  1481  		log.Println(status)
  1482  	}
  1483  }
  1484  
  1485  func main() {
  1486  	r := gin.New()
  1487  	r.Use(Logger())
  1488  
  1489  	r.GET("/test", func(c *gin.Context) {
  1490  		example := c.MustGet("example").(string)
  1491  
  1492  		// it would print: "12345"
  1493  		log.Println(example)
  1494  	})
  1495  
  1496  	// Listen and serve on 0.0.0.0:8080
  1497  	r.Run(":8080")
  1498  }
  1499  ```
  1500  
  1501  ### Using BasicAuth() middleware
  1502  
  1503  ```go
  1504  // simulate some private data
  1505  var secrets = gin.H{
  1506  	"foo":    gin.H{"email": "foo@bar.com", "phone": "123433"},
  1507  	"austin": gin.H{"email": "austin@example.com", "phone": "666"},
  1508  	"lena":   gin.H{"email": "lena@guapa.com", "phone": "523443"},
  1509  }
  1510  
  1511  func main() {
  1512  	r := gin.Default()
  1513  
  1514  	// Group using gin.BasicAuth() middleware
  1515  	// gin.Accounts is a shortcut for map[string]string
  1516  	authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{
  1517  		"foo":    "bar",
  1518  		"austin": "1234",
  1519  		"lena":   "hello2",
  1520  		"manu":   "4321",
  1521  	}))
  1522  
  1523  	// /admin/secrets endpoint
  1524  	// hit "localhost:8080/admin/secrets
  1525  	authorized.GET("/secrets", func(c *gin.Context) {
  1526  		// get user, it was set by the BasicAuth middleware
  1527  		user := c.MustGet(gin.AuthUserKey).(string)
  1528  		if secret, ok := secrets[user]; ok {
  1529  			c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})
  1530  		} else {
  1531  			c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("})
  1532  		}
  1533  	})
  1534  
  1535  	// Listen and serve on 0.0.0.0:8080
  1536  	r.Run(":8080")
  1537  }
  1538  ```
  1539  
  1540  ### Goroutines inside a middleware
  1541  
  1542  When starting new Goroutines inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy.
  1543  
  1544  ```go
  1545  func main() {
  1546  	r := gin.Default()
  1547  
  1548  	r.GET("/long_async", func(c *gin.Context) {
  1549  		// create copy to be used inside the goroutine
  1550  		cCp := c.Copy()
  1551  		go func() {
  1552  			// simulate a long task with time.Sleep(). 5 seconds
  1553  			time.Sleep(5 * time.Second)
  1554  
  1555  			// note that you are using the copied context "cCp", IMPORTANT
  1556  			log.Println("Done! in path " + cCp.Request.URL.Path)
  1557  		}()
  1558  	})
  1559  
  1560  	r.GET("/long_sync", func(c *gin.Context) {
  1561  		// simulate a long task with time.Sleep(). 5 seconds
  1562  		time.Sleep(5 * time.Second)
  1563  
  1564  		// since we are NOT using a goroutine, we do not have to copy the context
  1565  		log.Println("Done! in path " + c.Request.URL.Path)
  1566  	})
  1567  
  1568  	// Listen and serve on 0.0.0.0:8080
  1569  	r.Run(":8080")
  1570  }
  1571  ```
  1572  
  1573  ### Custom HTTP configuration
  1574  
  1575  Use `http.ListenAndServe()` directly, like this:
  1576  
  1577  ```go
  1578  func main() {
  1579  	router := gin.Default()
  1580  	http.ListenAndServe(":8080", router)
  1581  }
  1582  ```
  1583  or
  1584  
  1585  ```go
  1586  func main() {
  1587  	router := gin.Default()
  1588  
  1589  	s := &http.Server{
  1590  		Addr:           ":8080",
  1591  		Handler:        router,
  1592  		ReadTimeout:    10 * time.Second,
  1593  		WriteTimeout:   10 * time.Second,
  1594  		MaxHeaderBytes: 1 << 20,
  1595  	}
  1596  	s.ListenAndServe()
  1597  }
  1598  ```
  1599  
  1600  ### Support Let's Encrypt
  1601  
  1602  example for 1-line LetsEncrypt HTTPS servers.
  1603  
  1604  ```go
  1605  package main
  1606  
  1607  import (
  1608  	"log"
  1609  
  1610  	"github.com/gin-gonic/autotls"
  1611  	"github.com/hellobchain/third_party/gin"
  1612  )
  1613  
  1614  func main() {
  1615  	r := gin.Default()
  1616  
  1617  	// Ping handler
  1618  	r.GET("/ping", func(c *gin.Context) {
  1619  		c.String(200, "pong")
  1620  	})
  1621  
  1622  	log.Fatal(autotls.Run(r, "example1.com", "example2.com"))
  1623  }
  1624  ```
  1625  
  1626  example for custom autocert manager.
  1627  
  1628  ```go
  1629  package main
  1630  
  1631  import (
  1632  	"log"
  1633  
  1634  	"github.com/gin-gonic/autotls"
  1635  	"github.com/hellobchain/third_party/gin"
  1636  	"golang.org/x/crypto/acme/autocert"
  1637  )
  1638  
  1639  func main() {
  1640  	r := gin.Default()
  1641  
  1642  	// Ping handler
  1643  	r.GET("/ping", func(c *gin.Context) {
  1644  		c.String(200, "pong")
  1645  	})
  1646  
  1647  	m := autocert.Manager{
  1648  		Prompt:     autocert.AcceptTOS,
  1649  		HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
  1650  		Cache:      autocert.DirCache("/var/www/.cache"),
  1651  	}
  1652  
  1653  	log.Fatal(autotls.RunWithManager(r, &m))
  1654  }
  1655  ```
  1656  
  1657  ### Run multiple service using Gin
  1658  
  1659  See the [question](https://github.com/gin-gonic/gin/issues/346) and try the following example:
  1660  
  1661  ```go
  1662  package main
  1663  
  1664  import (
  1665  	"log"
  1666  	"github.com/hellobchain/newcryptosm/http"
  1667  	"time"
  1668  
  1669  	"github.com/hellobchain/third_party/gin"
  1670  	"golang.org/x/sync/errgroup"
  1671  )
  1672  
  1673  var (
  1674  	g errgroup.Group
  1675  )
  1676  
  1677  func router01() http.Handler {
  1678  	e := gin.New()
  1679  	e.Use(gin.Recovery())
  1680  	e.GET("/", func(c *gin.Context) {
  1681  		c.JSON(
  1682  			http.StatusOK,
  1683  			gin.H{
  1684  				"code":  http.StatusOK,
  1685  				"error": "Welcome server 01",
  1686  			},
  1687  		)
  1688  	})
  1689  
  1690  	return e
  1691  }
  1692  
  1693  func router02() http.Handler {
  1694  	e := gin.New()
  1695  	e.Use(gin.Recovery())
  1696  	e.GET("/", func(c *gin.Context) {
  1697  		c.JSON(
  1698  			http.StatusOK,
  1699  			gin.H{
  1700  				"code":  http.StatusOK,
  1701  				"error": "Welcome server 02",
  1702  			},
  1703  		)
  1704  	})
  1705  
  1706  	return e
  1707  }
  1708  
  1709  func main() {
  1710  	server01 := &http.Server{
  1711  		Addr:         ":8080",
  1712  		Handler:      router01(),
  1713  		ReadTimeout:  5 * time.Second,
  1714  		WriteTimeout: 10 * time.Second,
  1715  	}
  1716  
  1717  	server02 := &http.Server{
  1718  		Addr:         ":8081",
  1719  		Handler:      router02(),
  1720  		ReadTimeout:  5 * time.Second,
  1721  		WriteTimeout: 10 * time.Second,
  1722  	}
  1723  
  1724  	g.Go(func() error {
  1725  		err := server01.ListenAndServe()
  1726  		if err != nil && err != http.ErrServerClosed {
  1727  			log.Fatal(err)
  1728  		}
  1729  		return err
  1730  	})
  1731  
  1732  	g.Go(func() error {
  1733  		err := server02.ListenAndServe()
  1734  		if err != nil && err != http.ErrServerClosed {
  1735  			log.Fatal(err)
  1736  		}
  1737  		return err
  1738  	})
  1739  
  1740  	if err := g.Wait(); err != nil {
  1741  		log.Fatal(err)
  1742  	}
  1743  }
  1744  ```
  1745  
  1746  ### Graceful shutdown or restart
  1747  
  1748  There are a few approaches you can use to perform a graceful shutdown or restart. You can make use of third-party packages specifically built for that, or you can manually do the same with the functions and methods from the built-in packages.
  1749  
  1750  #### Third-party packages
  1751  
  1752  We can use [fvbock/endless](https://github.com/fvbock/endless) to replace the default `ListenAndServe`. Refer to issue [#296](https://github.com/gin-gonic/gin/issues/296) for more details.
  1753  
  1754  ```go
  1755  router := gin.Default()
  1756  router.GET("/", handler)
  1757  // [...]
  1758  endless.ListenAndServe(":4242", router)
  1759  ```
  1760  
  1761  Alternatives:
  1762  
  1763  * [manners](https://github.com/braintree/manners): A polite Go HTTP server that shuts down gracefully.
  1764  * [graceful](https://github.com/tylerb/graceful): Graceful is a Go package enabling graceful shutdown of an http.Handler server.
  1765  * [grace](https://github.com/facebookgo/grace): Graceful restart & zero downtime deploy for Go servers.
  1766  
  1767  #### Manually
  1768  
  1769  In case you are using Go 1.8 or a later version, you may not need to use those libraries. Consider using `http.Server`'s built-in [Shutdown()](https://golang.org/pkg/net/http/#Server.Shutdown) method for graceful shutdowns. The example below describes its usage, and we've got more examples using gin [here](https://github.com/gin-gonic/examples/tree/master/graceful-shutdown).
  1770  
  1771  ```go
  1772  // +build go1.8
  1773  
  1774  package main
  1775  
  1776  import (
  1777  	"context"
  1778  	"log"
  1779  	"github.com/hellobchain/newcryptosm/http"
  1780  	"os"
  1781  	"os/signal"
  1782  	"syscall"
  1783  	"time"
  1784  
  1785  	"github.com/hellobchain/third_party/gin"
  1786  )
  1787  
  1788  func main() {
  1789  	router := gin.Default()
  1790  	router.GET("/", func(c *gin.Context) {
  1791  		time.Sleep(5 * time.Second)
  1792  		c.String(http.StatusOK, "Welcome Gin Server")
  1793  	})
  1794  
  1795  	srv := &http.Server{
  1796  		Addr:    ":8080",
  1797  		Handler: router,
  1798  	}
  1799  
  1800  	// Initializing the server in a goroutine so that
  1801  	// it won't block the graceful shutdown handling below
  1802  	go func() {
  1803  		if err := srv.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) {
  1804  			log.Printf("listen: %s\n", err)
  1805  		}
  1806  	}()
  1807  
  1808  	// Wait for interrupt signal to gracefully shutdown the server with
  1809  	// a timeout of 5 seconds.
  1810  	quit := make(chan os.Signal)
  1811  	// kill (no param) default send syscall.SIGTERM
  1812  	// kill -2 is syscall.SIGINT
  1813  	// kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
  1814  	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
  1815  	<-quit
  1816  	log.Println("Shutting down server...")
  1817  
  1818  	// The context is used to inform the server it has 5 seconds to finish
  1819  	// the request it is currently handling
  1820  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  1821  	defer cancel()
  1822  
  1823  	if err := srv.Shutdown(ctx); err != nil {
  1824  		log.Fatal("Server forced to shutdown:", err)
  1825  	}
  1826  
  1827  	log.Println("Server exiting")
  1828  }
  1829  ```
  1830  
  1831  ### Build a single binary with templates
  1832  
  1833  You can build a server into a single binary containing templates by using [go-assets][].
  1834  
  1835  [go-assets]: https://github.com/jessevdk/go-assets
  1836  
  1837  ```go
  1838  func main() {
  1839  	r := gin.New()
  1840  
  1841  	t, err := loadTemplate()
  1842  	if err != nil {
  1843  		panic(err)
  1844  	}
  1845  	r.SetHTMLTemplate(t)
  1846  
  1847  	r.GET("/", func(c *gin.Context) {
  1848  		c.HTML(http.StatusOK, "/html/index.tmpl",nil)
  1849  	})
  1850  	r.Run(":8080")
  1851  }
  1852  
  1853  // loadTemplate loads templates embedded by go-assets-builder
  1854  func loadTemplate() (*template.Template, error) {
  1855  	t := template.New("")
  1856  	for name, file := range Assets.Files {
  1857  		defer file.Close()
  1858  		if file.IsDir() || !strings.HasSuffix(name, ".tmpl") {
  1859  			continue
  1860  		}
  1861  		h, err := ioutil.ReadAll(file)
  1862  		if err != nil {
  1863  			return nil, err
  1864  		}
  1865  		t, err = t.New(name).Parse(string(h))
  1866  		if err != nil {
  1867  			return nil, err
  1868  		}
  1869  	}
  1870  	return t, nil
  1871  }
  1872  ```
  1873  
  1874  See a complete example in the `https://github.com/gin-gonic/examples/tree/master/assets-in-binary` directory.
  1875  
  1876  ### Bind form-data request with custom struct
  1877  
  1878  The follow example using custom struct:
  1879  
  1880  ```go
  1881  type StructA struct {
  1882      FieldA string `form:"field_a"`
  1883  }
  1884  
  1885  type StructB struct {
  1886      NestedStruct StructA
  1887      FieldB string `form:"field_b"`
  1888  }
  1889  
  1890  type StructC struct {
  1891      NestedStructPointer *StructA
  1892      FieldC string `form:"field_c"`
  1893  }
  1894  
  1895  type StructD struct {
  1896      NestedAnonyStruct struct {
  1897          FieldX string `form:"field_x"`
  1898      }
  1899      FieldD string `form:"field_d"`
  1900  }
  1901  
  1902  func GetDataB(c *gin.Context) {
  1903      var b StructB
  1904      c.Bind(&b)
  1905      c.JSON(200, gin.H{
  1906          "a": b.NestedStruct,
  1907          "b": b.FieldB,
  1908      })
  1909  }
  1910  
  1911  func GetDataC(c *gin.Context) {
  1912      var b StructC
  1913      c.Bind(&b)
  1914      c.JSON(200, gin.H{
  1915          "a": b.NestedStructPointer,
  1916          "c": b.FieldC,
  1917      })
  1918  }
  1919  
  1920  func GetDataD(c *gin.Context) {
  1921      var b StructD
  1922      c.Bind(&b)
  1923      c.JSON(200, gin.H{
  1924          "x": b.NestedAnonyStruct,
  1925          "d": b.FieldD,
  1926      })
  1927  }
  1928  
  1929  func main() {
  1930      r := gin.Default()
  1931      r.GET("/getb", GetDataB)
  1932      r.GET("/getc", GetDataC)
  1933      r.GET("/getd", GetDataD)
  1934  
  1935      r.Run()
  1936  }
  1937  ```
  1938  
  1939  Using the command `curl` command result:
  1940  
  1941  ```
  1942  $ curl "http://localhost:8080/getb?field_a=hello&field_b=world"
  1943  {"a":{"FieldA":"hello"},"b":"world"}
  1944  $ curl "http://localhost:8080/getc?field_a=hello&field_c=world"
  1945  {"a":{"FieldA":"hello"},"c":"world"}
  1946  $ curl "http://localhost:8080/getd?field_x=hello&field_d=world"
  1947  {"d":"world","x":{"FieldX":"hello"}}
  1948  ```
  1949  
  1950  ### Try to bind body into different structs
  1951  
  1952  The normal methods for binding request body consumes `c.Request.Body` and they
  1953  cannot be called multiple times.
  1954  
  1955  ```go
  1956  type formA struct {
  1957    Foo string `json:"foo" xml:"foo" binding:"required"`
  1958  }
  1959  
  1960  type formB struct {
  1961    Bar string `json:"bar" xml:"bar" binding:"required"`
  1962  }
  1963  
  1964  func SomeHandler(c *gin.Context) {
  1965    objA := formA{}
  1966    objB := formB{}
  1967    // This c.ShouldBind consumes c.Request.Body and it cannot be reused.
  1968    if errA := c.ShouldBind(&objA); errA == nil {
  1969      c.String(http.StatusOK, `the body should be formA`)
  1970    // Always an error is occurred by this because c.Request.Body is EOF now.
  1971    } else if errB := c.ShouldBind(&objB); errB == nil {
  1972      c.String(http.StatusOK, `the body should be formB`)
  1973    } else {
  1974      ...
  1975    }
  1976  }
  1977  ```
  1978  
  1979  For this, you can use `c.ShouldBindBodyWith`.
  1980  
  1981  ```go
  1982  func SomeHandler(c *gin.Context) {
  1983    objA := formA{}
  1984    objB := formB{}
  1985    // This reads c.Request.Body and stores the result into the context.
  1986    if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil {
  1987      c.String(http.StatusOK, `the body should be formA`)
  1988    // At this time, it reuses body stored in the context.
  1989    } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
  1990      c.String(http.StatusOK, `the body should be formB JSON`)
  1991    // And it can accepts other formats
  1992    } else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {
  1993      c.String(http.StatusOK, `the body should be formB XML`)
  1994    } else {
  1995      ...
  1996    }
  1997  }
  1998  ```
  1999  
  2000  * `c.ShouldBindBodyWith` stores body into the context before binding. This has
  2001  a slight impact to performance, so you should not use this method if you are
  2002  enough to call binding at once.
  2003  * This feature is only needed for some formats -- `JSON`, `XML`, `MsgPack`,
  2004  `ProtoBuf`. For other formats, `Query`, `Form`, `FormPost`, `FormMultipart`,
  2005  can be called by `c.ShouldBind()` multiple times without any damage to
  2006  performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)).
  2007  
  2008  ### http2 server push
  2009  
  2010  http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information.
  2011  
  2012  ```go
  2013  package main
  2014  
  2015  import (
  2016  	"html/template"
  2017  	"log"
  2018  
  2019  	"github.com/hellobchain/third_party/gin"
  2020  )
  2021  
  2022  var html = template.Must(template.New("https").Parse(`
  2023  <html>
  2024  <head>
  2025    <title>Https Test</title>
  2026    <script src="/assets/app.js"></script>
  2027  </head>
  2028  <body>
  2029    <h1 style="color:red;">Welcome, Ginner!</h1>
  2030  </body>
  2031  </html>
  2032  `))
  2033  
  2034  func main() {
  2035  	r := gin.Default()
  2036  	r.Static("/assets", "./assets")
  2037  	r.SetHTMLTemplate(html)
  2038  
  2039  	r.GET("/", func(c *gin.Context) {
  2040  		if pusher := c.Writer.Pusher(); pusher != nil {
  2041  			// use pusher.Push() to do server push
  2042  			if err := pusher.Push("/assets/app.js", nil); err != nil {
  2043  				log.Printf("Failed to push: %v", err)
  2044  			}
  2045  		}
  2046  		c.HTML(200, "https", gin.H{
  2047  			"status": "success",
  2048  		})
  2049  	})
  2050  
  2051  	// Listen and Server in https://127.0.0.1:8080
  2052  	r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key")
  2053  }
  2054  ```
  2055  
  2056  ### Define format for the log of routes
  2057  
  2058  The default log of routes is:
  2059  ```
  2060  [GIN-debug] POST   /foo                      --> main.main.func1 (3 handlers)
  2061  [GIN-debug] GET    /bar                      --> main.main.func2 (3 handlers)
  2062  [GIN-debug] GET    /status                   --> main.main.func3 (3 handlers)
  2063  ```
  2064  
  2065  If you want to log this information in given format (e.g. JSON, key values or something else), then you can define this format with `gin.DebugPrintRouteFunc`.
  2066  In the example below, we log all routes with standard log package but you can use another log tools that suits of your needs.
  2067  ```go
  2068  import (
  2069  	"log"
  2070  	"github.com/hellobchain/newcryptosm/http"
  2071  
  2072  	"github.com/hellobchain/third_party/gin"
  2073  )
  2074  
  2075  func main() {
  2076  	r := gin.Default()
  2077  	gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
  2078  		log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers)
  2079  	}
  2080  
  2081  	r.POST("/foo", func(c *gin.Context) {
  2082  		c.JSON(http.StatusOK, "foo")
  2083  	})
  2084  
  2085  	r.GET("/bar", func(c *gin.Context) {
  2086  		c.JSON(http.StatusOK, "bar")
  2087  	})
  2088  
  2089  	r.GET("/status", func(c *gin.Context) {
  2090  		c.JSON(http.StatusOK, "ok")
  2091  	})
  2092  
  2093  	// Listen and Server in http://0.0.0.0:8080
  2094  	r.Run()
  2095  }
  2096  ```
  2097  
  2098  ### Set and get a cookie
  2099  
  2100  ```go
  2101  import (
  2102      "fmt"
  2103  
  2104      "github.com/hellobchain/third_party/gin"
  2105  )
  2106  
  2107  func main() {
  2108  
  2109      router := gin.Default()
  2110  
  2111      router.GET("/cookie", func(c *gin.Context) {
  2112  
  2113          cookie, err := c.Cookie("gin_cookie")
  2114  
  2115          if err != nil {
  2116              cookie = "NotSet"
  2117              c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true)
  2118          }
  2119  
  2120          fmt.Printf("Cookie value: %s \n", cookie)
  2121      })
  2122  
  2123      router.Run()
  2124  }
  2125  ```
  2126  
  2127  ## Don't trust all proxies
  2128  
  2129  Gin lets you specify which headers to hold the real client IP (if any),
  2130  as well as specifying which proxies (or direct clients) you trust to
  2131  specify one of these headers.
  2132  
  2133  The `TrustedProxies` slice on your `gin.Engine` specifes network addresses or
  2134  network CIDRs from where clients which their request headers related to client
  2135  IP can be trusted. They can be IPv4 addresses, IPv4 CIDRs, IPv6 addresses or
  2136  IPv6 CIDRs.
  2137  
  2138  ```go
  2139  import (
  2140  	"fmt"
  2141  
  2142  	"github.com/hellobchain/third_party/gin"
  2143  )
  2144  
  2145  func main() {
  2146  
  2147  	router := gin.Default()
  2148  	router.TrustedProxies = []string{"192.168.1.2"}
  2149  
  2150  	router.GET("/", func(c *gin.Context) {
  2151  		// If the client is 192.168.1.2, use the X-Forwarded-For
  2152  		// header to deduce the original client IP from the trust-
  2153  		// worthy parts of that header.
  2154  		// Otherwise, simply return the direct client IP
  2155  		fmt.Printf("ClientIP: %s\n", c.ClientIP())
  2156  	})
  2157  	router.Run()
  2158  }
  2159  ```
  2160  
  2161  ## Testing
  2162  
  2163  The `net/http/httptest` package is preferable way for HTTP testing.
  2164  
  2165  ```go
  2166  package main
  2167  
  2168  func setupRouter() *gin.Engine {
  2169  	r := gin.Default()
  2170  	r.GET("/ping", func(c *gin.Context) {
  2171  		c.String(200, "pong")
  2172  	})
  2173  	return r
  2174  }
  2175  
  2176  func main() {
  2177  	r := setupRouter()
  2178  	r.Run(":8080")
  2179  }
  2180  ```
  2181  
  2182  Test for code example above:
  2183  
  2184  ```go
  2185  package main
  2186  
  2187  import (
  2188  	"github.com/hellobchain/newcryptosm/http"
  2189  	"github.com/hellobchain/newcryptosm/http/httptest"
  2190  	"testing"
  2191  
  2192  	"github.com/stretchr/testify/assert"
  2193  )
  2194  
  2195  func TestPingRoute(t *testing.T) {
  2196  	router := setupRouter()
  2197  
  2198  	w := httptest.NewRecorder()
  2199  	req, _ := http.NewRequest("GET", "/ping", nil)
  2200  	router.ServeHTTP(w, req)
  2201  
  2202  	assert.Equal(t, 200, w.Code)
  2203  	assert.Equal(t, "pong", w.Body.String())
  2204  }
  2205  ```
  2206  
  2207  ## Users
  2208  
  2209  Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework.
  2210  
  2211  * [gorush](https://github.com/appleboy/gorush): A push notification server written in Go.
  2212  * [fnproject](https://github.com/fnproject/fn): The container native, cloud agnostic serverless platform.
  2213  * [photoprism](https://github.com/photoprism/photoprism): Personal photo management powered by Go and Google TensorFlow.
  2214  * [krakend](https://github.com/devopsfaith/krakend): Ultra performant API Gateway with middlewares.
  2215  * [picfit](https://github.com/thoas/picfit): An image resizing server written in Go.
  2216  * [brigade](https://github.com/brigadecore/brigade): Event-based Scripting for Kubernetes.
  2217  * [dkron](https://github.com/distribworks/dkron): Distributed, fault tolerant job scheduling system.