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
15Gin 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
85To install Gin package, you need to install Go and set your Go workspace first.
86
871. 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
932. Import it in your code:
94
95```go
96import "github.com/gin-gonic/gin"
97```
98
993. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`.
100
101```go
102import "net/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
113package main
114
115import "github.com/gin-gonic/gin"
116
117func 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
135Gin 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
187Gin 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
195You 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
200func 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
223func 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
260func 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
278func 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```
298POST /post?id=1234&page=1 HTTP/1.1
299Content-Type: application/x-www-form-urlencoded
300
301name=manu&message=this_is_great
302```
303
304```go
305func 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```
322id: 1234; page: 1; name: manu; message: this_is_great
323```
324
325### Map as querystring or postform parameters
326
327```
328POST /post?ids[a]=1234&ids[b]=hello HTTP/1.1
329Content-Type: application/x-www-form-urlencoded
330
331names[first]=thinkerou&names[second]=tianou
332```
333
334```go
335func 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```
350ids: map[b:hello a:1234]; names: map[second:tianou first:thinkerou]
351```
352
353### Upload files
354
355#### Single file
356
357References 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
364func 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
382How to `curl`:
383
384```bash
385curl -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
392See the detail [example code](https://github.com/gin-gonic/examples/tree/master/upload-file/multiple).
393
394```go
395func 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
416How to `curl`:
417
418```bash
419curl -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
428func 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
453Use
454
455```go
456r := gin.New()
457```
458
459instead of
460
461```go
462// Default With the Logger and Recovery middleware already attached
463r := gin.Default()
464```
465
466
467### Using middleware
468```go
469func 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
508func 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
541func 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
563func 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
600By default, logs output on console should be colorized depending on the detected TTY.
601
602Never colorize logs:
603
604```go
605func 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
621Always colorize logs:
622
623```go
624func 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
642To 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
644Gin 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
646Note 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
648Also, 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
656When 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
658You 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
662type 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
667func 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
753When 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
757It 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
760package main
761
762import (
763	"net/http"
764	"time"
765
766	"github.com/gin-gonic/gin"
767	"github.com/gin-gonic/gin/binding"
768	"github.com/go-playground/validator/v10"
769)
770
771// Booking contains binded and validated data.
772type 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
777var 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
788func 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
799func 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.
821See 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
828package main
829
830import (
831	"log"
832
833	"github.com/gin-gonic/gin"
834)
835
836type Person struct {
837	Name    string `form:"name"`
838	Address string `form:"address"`
839}
840
841func main() {
842	route := gin.Default()
843	route.Any("/testing", startPage)
844	route.Run(":8085")
845}
846
847func 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
861See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292).
862
863```go
864package main
865
866import (
867	"log"
868	"time"
869
870	"github.com/gin-gonic/gin"
871)
872
873type 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
881func main() {
882	route := gin.Default()
883	route.GET("/testing", startPage)
884	route.Run(":8085")
885}
886
887func 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
904Test 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
911See the [detail information](https://github.com/gin-gonic/gin/issues/846).
912
913```go
914package main
915
916import "github.com/gin-gonic/gin"
917
918type Person struct {
919	ID string `uri:"id" binding:"required,uuid"`
920	Name string `uri:"name" binding:"required"`
921}
922
923func 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
937Test 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
946package main
947
948import (
949	"fmt"
950	"github.com/gin-gonic/gin"
951)
952
953type testHeader struct {
954	Rate   int    `header:"Rate"`
955	Domain string `header:"Domain"`
956}
957
958func 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
982See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092)
983
984main.go
985
986```go
987...
988
989type myForm struct {
990    Colors []string `form:"colors[]"`
991}
992
993...
994
995func 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
1005form.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
1020result:
1021
1022```
1023{"color":["red","green","blue"]}
1024```
1025
1026### Multipart/Urlencoded binding
1027
1028```go
1029type 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
1037func 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
1064Test 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
1072func 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
1123Using SecureJSON to prevent json hijacking. Default prepends `"while(1),"` to response body if the given struct is array values.
1124
1125```go
1126func 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
1145Using 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
1148func 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
1171Using AsciiJSON to Generates ASCII-only JSON with escaped non-ASCII characters.
1172
1173```go
1174func 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
1194Normally, 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.
1195This feature is unavailable in Go 1.6 and lower.
1196
1197```go
1198func 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
1223func 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
1237func 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
1255func 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
1281Using LoadHTMLGlob() or LoadHTMLFiles()
1282
1283```go
1284func 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
1297templates/index.tmpl
1298
1299```html
1300<html>
1301	<h1>
1302		{{ .title }}
1303	</h1>
1304</html>
1305```
1306
1307Using templates with same name in different directories
1308
1309```go
1310func 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
1327templates/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
1339templates/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
1353You can also use your own html template render
1354
1355```go
1356import "html/template"
1357
1358func 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
1368You 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
1378See the detail [example code](https://github.com/gin-gonic/examples/tree/master/template).
1379
1380main.go
1381
1382```go
1383import (
1384    "fmt"
1385    "html/template"
1386    "net/http"
1387    "time"
1388
1389    "github.com/gin-gonic/gin"
1390)
1391
1392func formatAsDate(t time.Time) string {
1393    year, month, day := t.Date()
1394    return fmt.Sprintf("%d%02d/%02d", year, month, day)
1395}
1396
1397func 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
1416raw.tmpl
1417
1418```html
1419Date: {[{.now | formatAsDate}]}
1420```
1421
1422Result:
1423```
1424Date: 2017/07/01
1425```
1426
1427### Multitemplate
1428
1429Gin 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
1433Issuing a HTTP redirect is easy. Both internal and external locations are supported.
1434
1435```go
1436r.GET("/test", func(c *gin.Context) {
1437	c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
1438})
1439```
1440
1441Issuing a HTTP redirect from POST. Refer to issue: [#444](https://github.com/gin-gonic/gin/issues/444)
1442```go
1443r.POST("/test", func(c *gin.Context) {
1444	c.Redirect(http.StatusFound, "/foo")
1445})
1446```
1447
1448Issuing a Router redirect, use `HandleContext` like below.
1449
1450``` go
1451r.GET("/test", func(c *gin.Context) {
1452    c.Request.URL.Path = "/test2"
1453    r.HandleContext(c)
1454})
1455r.GET("/test2", func(c *gin.Context) {
1456    c.JSON(200, gin.H{"hello": "world"})
1457})
1458```
1459
1460
1461### Custom Middleware
1462
1463```go
1464func 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
1485func 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
1505var 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
1511func 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
1542When 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
1545func 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
1575Use `http.ListenAndServe()` directly, like this:
1576
1577```go
1578func main() {
1579	router := gin.Default()
1580	http.ListenAndServe(":8080", router)
1581}
1582```
1583or
1584
1585```go
1586func 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
1602example for 1-line LetsEncrypt HTTPS servers.
1603
1604```go
1605package main
1606
1607import (
1608	"log"
1609
1610	"github.com/gin-gonic/autotls"
1611	"github.com/gin-gonic/gin"
1612)
1613
1614func 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
1626example for custom autocert manager.
1627
1628```go
1629package main
1630
1631import (
1632	"log"
1633
1634	"github.com/gin-gonic/autotls"
1635	"github.com/gin-gonic/gin"
1636	"golang.org/x/crypto/acme/autocert"
1637)
1638
1639func 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
1659See the [question](https://github.com/gin-gonic/gin/issues/346) and try the following example:
1660
1661```go
1662package main
1663
1664import (
1665	"log"
1666	"net/http"
1667	"time"
1668
1669	"github.com/gin-gonic/gin"
1670	"golang.org/x/sync/errgroup"
1671)
1672
1673var (
1674	g errgroup.Group
1675)
1676
1677func 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
1693func 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
1709func 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
1748There 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
1752We 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
1755router := gin.Default()
1756router.GET("/", handler)
1757// [...]
1758endless.ListenAndServe(":4242", router)
1759```
1760
1761Alternatives:
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
1769In 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
1774package main
1775
1776import (
1777	"context"
1778	"log"
1779	"net/http"
1780	"os"
1781	"os/signal"
1782	"syscall"
1783	"time"
1784
1785	"github.com/gin-gonic/gin"
1786)
1787
1788func 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
1833You 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
1838func 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
1854func 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
1874See 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
1878The follow example using custom struct:
1879
1880```go
1881type StructA struct {
1882    FieldA string `form:"field_a"`
1883}
1884
1885type StructB struct {
1886    NestedStruct StructA
1887    FieldB string `form:"field_b"`
1888}
1889
1890type StructC struct {
1891    NestedStructPointer *StructA
1892    FieldC string `form:"field_c"`
1893}
1894
1895type StructD struct {
1896    NestedAnonyStruct struct {
1897        FieldX string `form:"field_x"`
1898    }
1899    FieldD string `form:"field_d"`
1900}
1901
1902func 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
1911func 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
1920func 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
1929func 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
1939Using 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
1952The normal methods for binding request body consumes `c.Request.Body` and they
1953cannot be called multiple times.
1954
1955```go
1956type formA struct {
1957  Foo string `json:"foo" xml:"foo" binding:"required"`
1958}
1959
1960type formB struct {
1961  Bar string `json:"bar" xml:"bar" binding:"required"`
1962}
1963
1964func 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
1979For this, you can use `c.ShouldBindBodyWith`.
1980
1981```go
1982func 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
2001a slight impact to performance, so you should not use this method if you are
2002enough 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`,
2005can be called by `c.ShouldBind()` multiple times without any damage to
2006performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)).
2007
2008### http2 server push
2009
2010http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information.
2011
2012```go
2013package main
2014
2015import (
2016	"html/template"
2017	"log"
2018
2019	"github.com/gin-gonic/gin"
2020)
2021
2022var 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
2034func 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
2058The 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
2065If 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`.
2066In 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
2068import (
2069	"log"
2070	"net/http"
2071
2072	"github.com/gin-gonic/gin"
2073)
2074
2075func 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
2101import (
2102    "fmt"
2103
2104    "github.com/gin-gonic/gin"
2105)
2106
2107func 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
2129Gin lets you specify which headers to hold the real client IP (if any),
2130as well as specifying which proxies (or direct clients) you trust to
2131specify one of these headers.
2132
2133The `TrustedProxies` slice on your `gin.Engine` specifes network addresses or
2134network CIDRs from where clients which their request headers related to client
2135IP can be trusted. They can be IPv4 addresses, IPv4 CIDRs, IPv6 addresses or
2136IPv6 CIDRs.
2137
2138```go
2139import (
2140	"fmt"
2141
2142	"github.com/gin-gonic/gin"
2143)
2144
2145func 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
2163The `net/http/httptest` package is preferable way for HTTP testing.
2164
2165```go
2166package main
2167
2168func 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
2176func main() {
2177	r := setupRouter()
2178	r.Run(":8080")
2179}
2180```
2181
2182Test for code example above:
2183
2184```go
2185package main
2186
2187import (
2188	"net/http"
2189	"net/http/httptest"
2190	"testing"
2191
2192	"github.com/stretchr/testify/assert"
2193)
2194
2195func 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
2209Awesome 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.
2218