gin-1.3.0/ 0000775 0000000 0000000 00000000000 13334514714 0012275 5 ustar 00root root 0000000 0000000 gin-1.3.0/.github/ 0000775 0000000 0000000 00000000000 13334514714 0013635 5 ustar 00root root 0000000 0000000 gin-1.3.0/.github/ISSUE_TEMPLATE.md 0000664 0000000 0000000 00000000453 13334514714 0016344 0 ustar 00root root 0000000 0000000 - With issues:
- Use the search tool before opening a new issue.
- Please provide source code and commit sha if you found a bug.
- Review existing issues and provide feedback or react to them.
- gin version (or commit ref):
- git version:
- operating system:
## Description
## Screenshots
gin-1.3.0/.github/PULL_REQUEST_TEMPLATE.md 0000664 0000000 0000000 00000000626 13334514714 0017442 0 ustar 00root root 0000000 0000000 - With pull requests:
- Open your pull request against `master`
- Your pull request should have no more than two commits, if not you should squash them.
- It should pass all tests in the available continuous integrations systems such as TravisCI.
- You should add/modify tests to cover your proposed code changes.
- If your pull request contains a new feature, please document it on the README.
gin-1.3.0/.gitignore 0000664 0000000 0000000 00000000071 13334514714 0014263 0 ustar 00root root 0000000 0000000 vendor/*
!vendor/vendor.json
coverage.out
count.out
test
gin-1.3.0/.travis.yml 0000664 0000000 0000000 00000001151 13334514714 0014404 0 ustar 00root root 0000000 0000000 language: go
sudo: false
go:
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- master
git:
depth: 10
install:
- make install
go_import_path: github.com/gin-gonic/gin
script:
- make vet
- make fmt-check
- make embedmd
- make misspell-check
- make test
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/7f95bf605c4d356372f4
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false
gin-1.3.0/AUTHORS.md 0000664 0000000 0000000 00000010163 13334514714 0013745 0 ustar 00root root 0000000 0000000 List of all the awesome people working to make Gin the best Web Framework in Go.
## gin 1.x series authors
**Gin Core Team:** Bo-Yi Wu (@appleboy), 田欧 (@thinkerou), Javier Provecho (@javierprovecho)
## gin 0.x series authors
**Maintainers:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho)
People and companies, who have contributed, in alphabetical order.
**@858806258 (杰哥)**
- Fix typo in example
**@achedeuzot (Klemen Sever)**
- Fix newline debug printing
**@adammck (Adam Mckaig)**
- Add MIT license
**@AlexanderChen1989 (Alexander)**
- Typos in README
**@alexanderdidenko (Aleksandr Didenko)**
- Add support multipart/form-data
**@alexandernyquist (Alexander Nyquist)**
- Using template.Must to fix multiple return issue
- ★ Added support for OPTIONS verb
- ★ Setting response headers before calling WriteHeader
- Improved documentation for model binding
- ★ Added Content.Redirect()
- ★ Added tons of Unit tests
**@austinheap (Austin Heap)**
- Added travis CI integration
**@andredublin (Andre Dublin)**
- Fix typo in comment
**@bredov (Ludwig Valda Vasquez)**
- Fix html templating in debug mode
**@bluele (Jun Kimura)**
- Fixes code examples in README
**@chad-russell**
- ★ Support for serializing gin.H into XML
**@dickeyxxx (Jeff Dickey)**
- Typos in README
- Add example about serving static files
**@donileo (Adonis)**
- Add NoMethod handler
**@dutchcoders (DutchCoders)**
- ★ Fix security bug that allows client to spoof ip
- Fix typo. r.HTMLTemplates -> SetHTMLTemplate
**@el3ctro- (Joshua Loper)**
- Fix typo in example
**@ethankan (Ethan Kan)**
- Unsigned integers in binding
**(Evgeny Persienko)**
- Validate sub structures
**@frankbille (Frank Bille)**
- Add support for HTTP Realm Auth
**@fmd (Fareed Dudhia)**
- Fix typo. SetHTTPTemplate -> SetHTMLTemplate
**@ironiridis (Christopher Harrington)**
- Remove old reference
**@jammie-stackhouse (Jamie Stackhouse)**
- Add more shortcuts for router methods
**@jasonrhansen**
- Fix spelling and grammar errors in documentation
**@JasonSoft (Jason Lee)**
- Fix typo in comment
**@joiggama (Ignacio Galindo)**
- Add utf-8 charset header on renders
**@julienschmidt (Julien Schmidt)**
- gofmt the code examples
**@kelcecil (Kel Cecil)**
- Fix readme typo
**@kyledinh (Kyle Dinh)**
- Adds RunTLS()
**@LinusU (Linus Unnebäck)**
- Small fixes in README
**@loongmxbt (Saint Asky)**
- Fix typo in example
**@lucas-clemente (Lucas Clemente)**
- ★ work around path.Join removing trailing slashes from routes
**@mattn (Yasuhiro Matsumoto)**
- Improve color logger
**@mdigger (Dmitry Sedykh)**
- Fixes Form binding when content-type is x-www-form-urlencoded
- No repeat call c.Writer.Status() in gin.Logger
- Fixes Content-Type for json render
**@mirzac (Mirza Ceric)**
- Fix debug printing
**@mopemope (Yutaka Matsubara)**
- ★ Adds Godep support (Dependencies Manager)
- Fix variadic parameter in the flexible render API
- Fix Corrupted plain render
- Add Pluggable View Renderer Example
**@msemenistyi (Mykyta Semenistyi)**
- update Readme.md. Add code to String method
**@msoedov (Sasha Myasoedov)**
- ★ Adds tons of unit tests.
**@ngerakines (Nick Gerakines)**
- ★ Improves API, c.GET() doesn't panic
- Adds MustGet() method
**@r8k (Rajiv Kilaparti)**
- Fix Port usage in README.
**@rayrod2030 (Ray Rodriguez)**
- Fix typo in example
**@rns**
- Fix typo in example
**@RobAWilkinson (Robert Wilkinson)**
- Add example of forms and params
**@rogierlommers (Rogier Lommers)**
- Add updated static serve example
**@se77en (Damon Zhao)**
- Improve color logging
**@silasb (Silas Baronda)**
- Fixing quotes in README
**@SkuliOskarsson (Skuli Oskarsson)**
- Fixes some texts in README II
**@slimmy (Jimmy Pettersson)**
- Added messages for required bindings
**@smira (Andrey Smirnov)**
- Add support for ignored/unexported fields in binding
**@superalsrk (SRK.Lyu)**
- Update httprouter godeps
**@tebeka (Miki Tebeka)**
- Use net/http constants instead of numeric values
**@techjanitor**
- Update context.go reserved IPs
**@yosssi (Keiji Yoshida)**
- Fix link in README
**@yuyabee**
- Fixed README
gin-1.3.0/BENCHMARKS.md 0000664 0000000 0000000 00000150355 13334514714 0014245 0 ustar 00root root 0000000 0000000
## Benchmark System
**VM HOST:** DigitalOcean
**Machine:** 4 CPU, 8 GB RAM. Ubuntu 16.04.2 x64
**Date:** July 19th, 2017
**Go Version:** 1.8.3 linux/amd64
**Source:** [Go HTTP Router Benchmark](https://github.com/julienschmidt/go-http-routing-benchmark)
## Static Routes: 157
```
Gin: 30512 Bytes
HttpServeMux: 17344 Bytes
Ace: 30080 Bytes
Bear: 30472 Bytes
Beego: 96408 Bytes
Bone: 37904 Bytes
Denco: 10464 Bytes
Echo: 73680 Bytes
GocraftWeb: 55720 Bytes
Goji: 27200 Bytes
Gojiv2: 104464 Bytes
GoJsonRest: 136472 Bytes
GoRestful: 914904 Bytes
GorillaMux: 675568 Bytes
HttpRouter: 21128 Bytes
HttpTreeMux: 73448 Bytes
Kocha: 115072 Bytes
LARS: 30120 Bytes
Macaron: 37984 Bytes
Martini: 310832 Bytes
Pat: 20464 Bytes
Possum: 91328 Bytes
R2router: 23712 Bytes
Rivet: 23880 Bytes
Tango: 28008 Bytes
TigerTonic: 80368 Bytes
Traffic: 626480 Bytes
Vulcan: 369064 Bytes
```
## GithubAPI Routes: 203
```
Gin: 52672 Bytes
Ace: 48992 Bytes
Bear: 161592 Bytes
Beego: 147992 Bytes
Bone: 97728 Bytes
Denco: 36440 Bytes
Echo: 95672 Bytes
GocraftWeb: 95640 Bytes
Goji: 86088 Bytes
Gojiv2: 144392 Bytes
GoJsonRest: 134648 Bytes
GoRestful: 1410760 Bytes
GorillaMux: 1509488 Bytes
HttpRouter: 37464 Bytes
HttpTreeMux: 78800 Bytes
Kocha: 785408 Bytes
LARS: 49032 Bytes
Macaron: 132712 Bytes
Martini: 564352 Bytes
Pat: 21200 Bytes
Possum: 83888 Bytes
R2router: 47104 Bytes
Rivet: 42840 Bytes
Tango: 54584 Bytes
TigerTonic: 96384 Bytes
Traffic: 1061920 Bytes
Vulcan: 465296 Bytes
```
## GPlusAPI Routes: 13
```
Gin: 3968 Bytes
Ace: 3600 Bytes
Bear: 7112 Bytes
Beego: 10048 Bytes
Bone: 6480 Bytes
Denco: 3256 Bytes
Echo: 9000 Bytes
GocraftWeb: 7496 Bytes
Goji: 2912 Bytes
Gojiv2: 7376 Bytes
GoJsonRest: 11544 Bytes
GoRestful: 88776 Bytes
GorillaMux: 71488 Bytes
HttpRouter: 2712 Bytes
HttpTreeMux: 7440 Bytes
Kocha: 128880 Bytes
LARS: 3640 Bytes
Macaron: 8656 Bytes
Martini: 23936 Bytes
Pat: 1856 Bytes
Possum: 7248 Bytes
R2router: 3928 Bytes
Rivet: 3064 Bytes
Tango: 4912 Bytes
TigerTonic: 9408 Bytes
Traffic: 49472 Bytes
Vulcan: 25496 Bytes
```
## ParseAPI Routes: 26
```
Gin: 6928 Bytes
Ace: 6592 Bytes
Bear: 12320 Bytes
Beego: 18960 Bytes
Bone: 11024 Bytes
Denco: 4184 Bytes
Echo: 11168 Bytes
GocraftWeb: 12800 Bytes
Goji: 5232 Bytes
Gojiv2: 14464 Bytes
GoJsonRest: 14216 Bytes
GoRestful: 127368 Bytes
GorillaMux: 123016 Bytes
HttpRouter: 4976 Bytes
HttpTreeMux: 7848 Bytes
Kocha: 181712 Bytes
LARS: 6632 Bytes
Macaron: 13648 Bytes
Martini: 45952 Bytes
Pat: 2560 Bytes
Possum: 9200 Bytes
R2router: 7056 Bytes
Rivet: 5680 Bytes
Tango: 8664 Bytes
TigerTonic: 9840 Bytes
Traffic: 93480 Bytes
Vulcan: 44504 Bytes
```
## Static Routes
```
BenchmarkGin_StaticAll 50000 34506 ns/op 0 B/op 0 allocs/op
BenchmarkAce_StaticAll 30000 49657 ns/op 0 B/op 0 allocs/op
BenchmarkHttpServeMux_StaticAll 2000 1183737 ns/op 96 B/op 8 allocs/op
BenchmarkBeego_StaticAll 5000 412621 ns/op 57776 B/op 628 allocs/op
BenchmarkBear_StaticAll 10000 149242 ns/op 20336 B/op 461 allocs/op
BenchmarkBone_StaticAll 10000 118583 ns/op 0 B/op 0 allocs/op
BenchmarkDenco_StaticAll 100000 13247 ns/op 0 B/op 0 allocs/op
BenchmarkEcho_StaticAll 20000 79914 ns/op 5024 B/op 157 allocs/op
BenchmarkGocraftWeb_StaticAll 10000 211823 ns/op 46440 B/op 785 allocs/op
BenchmarkGoji_StaticAll 10000 109390 ns/op 0 B/op 0 allocs/op
BenchmarkGojiv2_StaticAll 3000 415533 ns/op 145696 B/op 1099 allocs/op
BenchmarkGoJsonRest_StaticAll 5000 364403 ns/op 51653 B/op 1727 allocs/op
BenchmarkGoRestful_StaticAll 500 2578579 ns/op 314936 B/op 3144 allocs/op
BenchmarkGorillaMux_StaticAll 500 2704856 ns/op 115648 B/op 1578 allocs/op
BenchmarkHttpRouter_StaticAll 100000 18541 ns/op 0 B/op 0 allocs/op
BenchmarkHttpTreeMux_StaticAll 100000 22332 ns/op 0 B/op 0 allocs/op
BenchmarkKocha_StaticAll 50000 31176 ns/op 0 B/op 0 allocs/op
BenchmarkLARS_StaticAll 50000 40840 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_StaticAll 5000 517656 ns/op 120576 B/op 1413 allocs/op
BenchmarkMartini_StaticAll 300 4462289 ns/op 125442 B/op 1717 allocs/op
BenchmarkPat_StaticAll 500 2157275 ns/op 533904 B/op 11123 allocs/op
BenchmarkPossum_StaticAll 10000 254701 ns/op 65312 B/op 471 allocs/op
BenchmarkR2router_StaticAll 10000 133956 ns/op 22608 B/op 628 allocs/op
BenchmarkRivet_StaticAll 30000 46812 ns/op 0 B/op 0 allocs/op
BenchmarkTango_StaticAll 5000 390613 ns/op 39225 B/op 1256 allocs/op
BenchmarkTigerTonic_StaticAll 20000 88060 ns/op 7504 B/op 157 allocs/op
BenchmarkTraffic_StaticAll 500 2910236 ns/op 729736 B/op 14287 allocs/op
BenchmarkVulcan_StaticAll 5000 277366 ns/op 15386 B/op 471 allocs/op
```
## Micro Benchmarks
```
BenchmarkGin_Param 20000000 113 ns/op 0 B/op 0 allocs/op
BenchmarkAce_Param 5000000 375 ns/op 32 B/op 1 allocs/op
BenchmarkBear_Param 1000000 1709 ns/op 456 B/op 5 allocs/op
BenchmarkBeego_Param 1000000 2484 ns/op 368 B/op 4 allocs/op
BenchmarkBone_Param 1000000 2391 ns/op 688 B/op 5 allocs/op
BenchmarkDenco_Param 10000000 240 ns/op 32 B/op 1 allocs/op
BenchmarkEcho_Param 5000000 366 ns/op 32 B/op 1 allocs/op
BenchmarkGocraftWeb_Param 1000000 2343 ns/op 648 B/op 8 allocs/op
BenchmarkGoji_Param 1000000 1197 ns/op 336 B/op 2 allocs/op
BenchmarkGojiv2_Param 1000000 2771 ns/op 944 B/op 8 allocs/op
BenchmarkGoJsonRest_Param 1000000 2993 ns/op 649 B/op 13 allocs/op
BenchmarkGoRestful_Param 200000 8860 ns/op 2296 B/op 21 allocs/op
BenchmarkGorillaMux_Param 500000 4461 ns/op 1056 B/op 11 allocs/op
BenchmarkHttpRouter_Param 10000000 175 ns/op 32 B/op 1 allocs/op
BenchmarkHttpTreeMux_Param 1000000 1167 ns/op 352 B/op 3 allocs/op
BenchmarkKocha_Param 3000000 429 ns/op 56 B/op 3 allocs/op
BenchmarkLARS_Param 10000000 134 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_Param 500000 4635 ns/op 1056 B/op 10 allocs/op
BenchmarkMartini_Param 200000 9933 ns/op 1072 B/op 10 allocs/op
BenchmarkPat_Param 1000000 2929 ns/op 648 B/op 12 allocs/op
BenchmarkPossum_Param 1000000 2503 ns/op 560 B/op 6 allocs/op
BenchmarkR2router_Param 1000000 1507 ns/op 432 B/op 5 allocs/op
BenchmarkRivet_Param 5000000 297 ns/op 48 B/op 1 allocs/op
BenchmarkTango_Param 1000000 1862 ns/op 248 B/op 8 allocs/op
BenchmarkTigerTonic_Param 500000 5660 ns/op 992 B/op 17 allocs/op
BenchmarkTraffic_Param 200000 8408 ns/op 1960 B/op 21 allocs/op
BenchmarkVulcan_Param 2000000 963 ns/op 98 B/op 3 allocs/op
BenchmarkAce_Param5 2000000 740 ns/op 160 B/op 1 allocs/op
BenchmarkBear_Param5 1000000 2777 ns/op 501 B/op 5 allocs/op
BenchmarkBeego_Param5 1000000 3740 ns/op 368 B/op 4 allocs/op
BenchmarkBone_Param5 1000000 2950 ns/op 736 B/op 5 allocs/op
BenchmarkDenco_Param5 2000000 644 ns/op 160 B/op 1 allocs/op
BenchmarkEcho_Param5 3000000 558 ns/op 32 B/op 1 allocs/op
BenchmarkGin_Param5 10000000 198 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_Param5 500000 3870 ns/op 920 B/op 11 allocs/op
BenchmarkGoji_Param5 1000000 1746 ns/op 336 B/op 2 allocs/op
BenchmarkGojiv2_Param5 1000000 3214 ns/op 1008 B/op 8 allocs/op
BenchmarkGoJsonRest_Param5 500000 5509 ns/op 1097 B/op 16 allocs/op
BenchmarkGoRestful_Param5 200000 11232 ns/op 2392 B/op 21 allocs/op
BenchmarkGorillaMux_Param5 300000 7777 ns/op 1184 B/op 11 allocs/op
BenchmarkHttpRouter_Param5 3000000 631 ns/op 160 B/op 1 allocs/op
BenchmarkHttpTreeMux_Param5 1000000 2800 ns/op 576 B/op 6 allocs/op
BenchmarkKocha_Param5 1000000 2053 ns/op 440 B/op 10 allocs/op
BenchmarkLARS_Param5 10000000 232 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_Param5 500000 5888 ns/op 1056 B/op 10 allocs/op
BenchmarkMartini_Param5 200000 12807 ns/op 1232 B/op 11 allocs/op
BenchmarkPat_Param5 300000 7320 ns/op 964 B/op 32 allocs/op
BenchmarkPossum_Param5 1000000 2495 ns/op 560 B/op 6 allocs/op
BenchmarkR2router_Param5 1000000 1844 ns/op 432 B/op 5 allocs/op
BenchmarkRivet_Param5 2000000 935 ns/op 240 B/op 1 allocs/op
BenchmarkTango_Param5 1000000 2327 ns/op 360 B/op 8 allocs/op
BenchmarkTigerTonic_Param5 100000 18514 ns/op 2551 B/op 43 allocs/op
BenchmarkTraffic_Param5 200000 11997 ns/op 2248 B/op 25 allocs/op
BenchmarkVulcan_Param5 1000000 1333 ns/op 98 B/op 3 allocs/op
BenchmarkAce_Param20 1000000 2031 ns/op 640 B/op 1 allocs/op
BenchmarkBear_Param20 200000 7285 ns/op 1664 B/op 5 allocs/op
BenchmarkBeego_Param20 300000 6224 ns/op 368 B/op 4 allocs/op
BenchmarkBone_Param20 200000 8023 ns/op 1903 B/op 5 allocs/op
BenchmarkDenco_Param20 1000000 2262 ns/op 640 B/op 1 allocs/op
BenchmarkEcho_Param20 1000000 1387 ns/op 32 B/op 1 allocs/op
BenchmarkGin_Param20 3000000 503 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_Param20 100000 14408 ns/op 3795 B/op 15 allocs/op
BenchmarkGoji_Param20 500000 5272 ns/op 1247 B/op 2 allocs/op
BenchmarkGojiv2_Param20 1000000 4163 ns/op 1248 B/op 8 allocs/op
BenchmarkGoJsonRest_Param20 100000 17866 ns/op 4485 B/op 20 allocs/op
BenchmarkGoRestful_Param20 100000 21022 ns/op 4724 B/op 23 allocs/op
BenchmarkGorillaMux_Param20 100000 17055 ns/op 3547 B/op 13 allocs/op
BenchmarkHttpRouter_Param20 1000000 1748 ns/op 640 B/op 1 allocs/op
BenchmarkHttpTreeMux_Param20 200000 12246 ns/op 3196 B/op 10 allocs/op
BenchmarkKocha_Param20 300000 6861 ns/op 1808 B/op 27 allocs/op
BenchmarkLARS_Param20 3000000 526 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_Param20 100000 13069 ns/op 2906 B/op 12 allocs/op
BenchmarkMartini_Param20 100000 23602 ns/op 3597 B/op 13 allocs/op
BenchmarkPat_Param20 50000 32143 ns/op 4688 B/op 111 allocs/op
BenchmarkPossum_Param20 1000000 2396 ns/op 560 B/op 6 allocs/op
BenchmarkR2router_Param20 200000 8907 ns/op 2283 B/op 7 allocs/op
BenchmarkRivet_Param20 1000000 3280 ns/op 1024 B/op 1 allocs/op
BenchmarkTango_Param20 500000 4640 ns/op 856 B/op 8 allocs/op
BenchmarkTigerTonic_Param20 20000 67581 ns/op 10532 B/op 138 allocs/op
BenchmarkTraffic_Param20 50000 40313 ns/op 7941 B/op 45 allocs/op
BenchmarkVulcan_Param20 1000000 2264 ns/op 98 B/op 3 allocs/op
BenchmarkAce_ParamWrite 3000000 532 ns/op 40 B/op 2 allocs/op
BenchmarkBear_ParamWrite 1000000 1778 ns/op 456 B/op 5 allocs/op
BenchmarkBeego_ParamWrite 1000000 2596 ns/op 376 B/op 5 allocs/op
BenchmarkBone_ParamWrite 1000000 2519 ns/op 688 B/op 5 allocs/op
BenchmarkDenco_ParamWrite 5000000 411 ns/op 32 B/op 1 allocs/op
BenchmarkEcho_ParamWrite 2000000 718 ns/op 40 B/op 2 allocs/op
BenchmarkGin_ParamWrite 5000000 283 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_ParamWrite 1000000 2561 ns/op 656 B/op 9 allocs/op
BenchmarkGoji_ParamWrite 1000000 1378 ns/op 336 B/op 2 allocs/op
BenchmarkGojiv2_ParamWrite 1000000 3128 ns/op 976 B/op 10 allocs/op
BenchmarkGoJsonRest_ParamWrite 500000 4446 ns/op 1128 B/op 18 allocs/op
BenchmarkGoRestful_ParamWrite 200000 10291 ns/op 2304 B/op 22 allocs/op
BenchmarkGorillaMux_ParamWrite 500000 5153 ns/op 1064 B/op 12 allocs/op
BenchmarkHttpRouter_ParamWrite 5000000 263 ns/op 32 B/op 1 allocs/op
BenchmarkHttpTreeMux_ParamWrite 1000000 1351 ns/op 352 B/op 3 allocs/op
BenchmarkKocha_ParamWrite 3000000 538 ns/op 56 B/op 3 allocs/op
BenchmarkLARS_ParamWrite 5000000 316 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_ParamWrite 500000 5756 ns/op 1160 B/op 14 allocs/op
BenchmarkMartini_ParamWrite 200000 13097 ns/op 1176 B/op 14 allocs/op
BenchmarkPat_ParamWrite 500000 4954 ns/op 1072 B/op 17 allocs/op
BenchmarkPossum_ParamWrite 1000000 2499 ns/op 560 B/op 6 allocs/op
BenchmarkR2router_ParamWrite 1000000 1531 ns/op 432 B/op 5 allocs/op
BenchmarkRivet_ParamWrite 3000000 570 ns/op 112 B/op 2 allocs/op
BenchmarkTango_ParamWrite 2000000 957 ns/op 136 B/op 4 allocs/op
BenchmarkTigerTonic_ParamWrite 200000 7025 ns/op 1424 B/op 23 allocs/op
BenchmarkTraffic_ParamWrite 200000 10112 ns/op 2384 B/op 25 allocs/op
BenchmarkVulcan_ParamWrite 1000000 1006 ns/op 98 B/op 3 allocs/op
```
## GitHub
```
BenchmarkGin_GithubStatic 10000000 156 ns/op 0 B/op 0 allocs/op
BenchmarkAce_GithubStatic 5000000 294 ns/op 0 B/op 0 allocs/op
BenchmarkBear_GithubStatic 2000000 893 ns/op 120 B/op 3 allocs/op
BenchmarkBeego_GithubStatic 1000000 2491 ns/op 368 B/op 4 allocs/op
BenchmarkBone_GithubStatic 50000 25300 ns/op 2880 B/op 60 allocs/op
BenchmarkDenco_GithubStatic 20000000 76.0 ns/op 0 B/op 0 allocs/op
BenchmarkEcho_GithubStatic 2000000 516 ns/op 32 B/op 1 allocs/op
BenchmarkGocraftWeb_GithubStatic 1000000 1448 ns/op 296 B/op 5 allocs/op
BenchmarkGoji_GithubStatic 3000000 496 ns/op 0 B/op 0 allocs/op
BenchmarkGojiv2_GithubStatic 1000000 2941 ns/op 928 B/op 7 allocs/op
BenchmarkGoRestful_GithubStatic 100000 27256 ns/op 3224 B/op 22 allocs/op
BenchmarkGoJsonRest_GithubStatic 1000000 2196 ns/op 329 B/op 11 allocs/op
BenchmarkGorillaMux_GithubStatic 50000 31617 ns/op 736 B/op 10 allocs/op
BenchmarkHttpRouter_GithubStatic 20000000 88.4 ns/op 0 B/op 0 allocs/op
BenchmarkHttpTreeMux_GithubStatic 10000000 134 ns/op 0 B/op 0 allocs/op
BenchmarkKocha_GithubStatic 20000000 113 ns/op 0 B/op 0 allocs/op
BenchmarkLARS_GithubStatic 10000000 195 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_GithubStatic 500000 3740 ns/op 768 B/op 9 allocs/op
BenchmarkMartini_GithubStatic 50000 27673 ns/op 768 B/op 9 allocs/op
BenchmarkPat_GithubStatic 100000 19470 ns/op 3648 B/op 76 allocs/op
BenchmarkPossum_GithubStatic 1000000 1729 ns/op 416 B/op 3 allocs/op
BenchmarkR2router_GithubStatic 2000000 879 ns/op 144 B/op 4 allocs/op
BenchmarkRivet_GithubStatic 10000000 231 ns/op 0 B/op 0 allocs/op
BenchmarkTango_GithubStatic 1000000 2325 ns/op 248 B/op 8 allocs/op
BenchmarkTigerTonic_GithubStatic 3000000 610 ns/op 48 B/op 1 allocs/op
BenchmarkTraffic_GithubStatic 20000 62973 ns/op 18904 B/op 148 allocs/op
BenchmarkVulcan_GithubStatic 1000000 1447 ns/op 98 B/op 3 allocs/op
BenchmarkAce_GithubParam 2000000 686 ns/op 96 B/op 1 allocs/op
BenchmarkBear_GithubParam 1000000 2155 ns/op 496 B/op 5 allocs/op
BenchmarkBeego_GithubParam 1000000 2713 ns/op 368 B/op 4 allocs/op
BenchmarkBone_GithubParam 100000 15088 ns/op 1760 B/op 18 allocs/op
BenchmarkDenco_GithubParam 2000000 629 ns/op 128 B/op 1 allocs/op
BenchmarkEcho_GithubParam 2000000 653 ns/op 32 B/op 1 allocs/op
BenchmarkGin_GithubParam 5000000 255 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GithubParam 1000000 3145 ns/op 712 B/op 9 allocs/op
BenchmarkGoji_GithubParam 1000000 1916 ns/op 336 B/op 2 allocs/op
BenchmarkGojiv2_GithubParam 1000000 3975 ns/op 1024 B/op 10 allocs/op
BenchmarkGoJsonRest_GithubParam 300000 4134 ns/op 713 B/op 14 allocs/op
BenchmarkGoRestful_GithubParam 50000 30782 ns/op 2360 B/op 21 allocs/op
BenchmarkGorillaMux_GithubParam 100000 17148 ns/op 1088 B/op 11 allocs/op
BenchmarkHttpRouter_GithubParam 3000000 523 ns/op 96 B/op 1 allocs/op
BenchmarkHttpTreeMux_GithubParam 1000000 1671 ns/op 384 B/op 4 allocs/op
BenchmarkKocha_GithubParam 1000000 1021 ns/op 128 B/op 5 allocs/op
BenchmarkLARS_GithubParam 5000000 283 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_GithubParam 500000 4270 ns/op 1056 B/op 10 allocs/op
BenchmarkMartini_GithubParam 100000 21728 ns/op 1152 B/op 11 allocs/op
BenchmarkPat_GithubParam 200000 11208 ns/op 2464 B/op 48 allocs/op
BenchmarkPossum_GithubParam 1000000 2334 ns/op 560 B/op 6 allocs/op
BenchmarkR2router_GithubParam 1000000 1487 ns/op 432 B/op 5 allocs/op
BenchmarkRivet_GithubParam 2000000 782 ns/op 96 B/op 1 allocs/op
BenchmarkTango_GithubParam 1000000 2653 ns/op 344 B/op 8 allocs/op
BenchmarkTigerTonic_GithubParam 300000 14073 ns/op 1440 B/op 24 allocs/op
BenchmarkTraffic_GithubParam 50000 29164 ns/op 5992 B/op 52 allocs/op
BenchmarkVulcan_GithubParam 1000000 2529 ns/op 98 B/op 3 allocs/op
BenchmarkAce_GithubAll 10000 134059 ns/op 13792 B/op 167 allocs/op
BenchmarkBear_GithubAll 5000 534445 ns/op 86448 B/op 943 allocs/op
BenchmarkBeego_GithubAll 3000 592444 ns/op 74705 B/op 812 allocs/op
BenchmarkBone_GithubAll 200 6957308 ns/op 698784 B/op 8453 allocs/op
BenchmarkDenco_GithubAll 10000 158819 ns/op 20224 B/op 167 allocs/op
BenchmarkEcho_GithubAll 10000 154700 ns/op 6496 B/op 203 allocs/op
BenchmarkGin_GithubAll 30000 48375 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GithubAll 3000 570806 ns/op 131656 B/op 1686 allocs/op
BenchmarkGoji_GithubAll 2000 818034 ns/op 56112 B/op 334 allocs/op
BenchmarkGojiv2_GithubAll 2000 1213973 ns/op 274768 B/op 3712 allocs/op
BenchmarkGoJsonRest_GithubAll 2000 785796 ns/op 134371 B/op 2737 allocs/op
BenchmarkGoRestful_GithubAll 300 5238188 ns/op 689672 B/op 4519 allocs/op
BenchmarkGorillaMux_GithubAll 100 10257726 ns/op 211840 B/op 2272 allocs/op
BenchmarkHttpRouter_GithubAll 20000 105414 ns/op 13792 B/op 167 allocs/op
BenchmarkHttpTreeMux_GithubAll 10000 319934 ns/op 65856 B/op 671 allocs/op
BenchmarkKocha_GithubAll 10000 209442 ns/op 23304 B/op 843 allocs/op
BenchmarkLARS_GithubAll 20000 62565 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_GithubAll 2000 1161270 ns/op 204194 B/op 2000 allocs/op
BenchmarkMartini_GithubAll 200 9991713 ns/op 226549 B/op 2325 allocs/op
BenchmarkPat_GithubAll 200 5590793 ns/op 1499568 B/op 27435 allocs/op
BenchmarkPossum_GithubAll 10000 319768 ns/op 84448 B/op 609 allocs/op
BenchmarkR2router_GithubAll 10000 305134 ns/op 77328 B/op 979 allocs/op
BenchmarkRivet_GithubAll 10000 132134 ns/op 16272 B/op 167 allocs/op
BenchmarkTango_GithubAll 3000 552754 ns/op 63826 B/op 1618 allocs/op
BenchmarkTigerTonic_GithubAll 1000 1439483 ns/op 239104 B/op 5374 allocs/op
BenchmarkTraffic_GithubAll 100 11383067 ns/op 2659329 B/op 21848 allocs/op
BenchmarkVulcan_GithubAll 5000 394253 ns/op 19894 B/op 609 allocs/op
```
## Google+
```
BenchmarkGin_GPlusStatic 10000000 183 ns/op 0 B/op 0 allocs/op
BenchmarkAce_GPlusStatic 5000000 276 ns/op 0 B/op 0 allocs/op
BenchmarkBear_GPlusStatic 2000000 652 ns/op 104 B/op 3 allocs/op
BenchmarkBeego_GPlusStatic 1000000 2239 ns/op 368 B/op 4 allocs/op
BenchmarkBone_GPlusStatic 5000000 380 ns/op 32 B/op 1 allocs/op
BenchmarkDenco_GPlusStatic 30000000 45.8 ns/op 0 B/op 0 allocs/op
BenchmarkEcho_GPlusStatic 5000000 338 ns/op 32 B/op 1 allocs/op
BenchmarkGocraftWeb_GPlusStatic 1000000 1158 ns/op 280 B/op 5 allocs/op
BenchmarkGoji_GPlusStatic 5000000 331 ns/op 0 B/op 0 allocs/op
BenchmarkGojiv2_GPlusStatic 1000000 2106 ns/op 928 B/op 7 allocs/op
BenchmarkGoJsonRest_GPlusStatic 1000000 1626 ns/op 329 B/op 11 allocs/op
BenchmarkGoRestful_GPlusStatic 300000 7598 ns/op 1976 B/op 20 allocs/op
BenchmarkGorillaMux_GPlusStatic 1000000 2629 ns/op 736 B/op 10 allocs/op
BenchmarkHttpRouter_GPlusStatic 30000000 52.5 ns/op 0 B/op 0 allocs/op
BenchmarkHttpTreeMux_GPlusStatic 20000000 85.8 ns/op 0 B/op 0 allocs/op
BenchmarkKocha_GPlusStatic 20000000 89.2 ns/op 0 B/op 0 allocs/op
BenchmarkLARS_GPlusStatic 10000000 162 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_GPlusStatic 500000 3479 ns/op 768 B/op 9 allocs/op
BenchmarkMartini_GPlusStatic 200000 9092 ns/op 768 B/op 9 allocs/op
BenchmarkPat_GPlusStatic 3000000 493 ns/op 96 B/op 2 allocs/op
BenchmarkPossum_GPlusStatic 1000000 1467 ns/op 416 B/op 3 allocs/op
BenchmarkR2router_GPlusStatic 2000000 788 ns/op 144 B/op 4 allocs/op
BenchmarkRivet_GPlusStatic 20000000 114 ns/op 0 B/op 0 allocs/op
BenchmarkTango_GPlusStatic 1000000 1534 ns/op 200 B/op 8 allocs/op
BenchmarkTigerTonic_GPlusStatic 5000000 282 ns/op 32 B/op 1 allocs/op
BenchmarkTraffic_GPlusStatic 500000 3798 ns/op 1192 B/op 15 allocs/op
BenchmarkVulcan_GPlusStatic 2000000 1125 ns/op 98 B/op 3 allocs/op
BenchmarkAce_GPlusParam 3000000 528 ns/op 64 B/op 1 allocs/op
BenchmarkBear_GPlusParam 1000000 1570 ns/op 480 B/op 5 allocs/op
BenchmarkBeego_GPlusParam 1000000 2369 ns/op 368 B/op 4 allocs/op
BenchmarkBone_GPlusParam 1000000 2028 ns/op 688 B/op 5 allocs/op
BenchmarkDenco_GPlusParam 5000000 385 ns/op 64 B/op 1 allocs/op
BenchmarkEcho_GPlusParam 3000000 441 ns/op 32 B/op 1 allocs/op
BenchmarkGin_GPlusParam 10000000 174 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GPlusParam 1000000 2033 ns/op 648 B/op 8 allocs/op
BenchmarkGoji_GPlusParam 1000000 1399 ns/op 336 B/op 2 allocs/op
BenchmarkGojiv2_GPlusParam 1000000 2641 ns/op 944 B/op 8 allocs/op
BenchmarkGoJsonRest_GPlusParam 1000000 2824 ns/op 649 B/op 13 allocs/op
BenchmarkGoRestful_GPlusParam 200000 8875 ns/op 2296 B/op 21 allocs/op
BenchmarkGorillaMux_GPlusParam 200000 6291 ns/op 1056 B/op 11 allocs/op
BenchmarkHttpRouter_GPlusParam 5000000 316 ns/op 64 B/op 1 allocs/op
BenchmarkHttpTreeMux_GPlusParam 1000000 1129 ns/op 352 B/op 3 allocs/op
BenchmarkKocha_GPlusParam 3000000 538 ns/op 56 B/op 3 allocs/op
BenchmarkLARS_GPlusParam 10000000 198 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_GPlusParam 500000 3554 ns/op 1056 B/op 10 allocs/op
BenchmarkMartini_GPlusParam 200000 9831 ns/op 1072 B/op 10 allocs/op
BenchmarkPat_GPlusParam 1000000 2706 ns/op 688 B/op 12 allocs/op
BenchmarkPossum_GPlusParam 1000000 2297 ns/op 560 B/op 6 allocs/op
BenchmarkR2router_GPlusParam 1000000 1318 ns/op 432 B/op 5 allocs/op
BenchmarkRivet_GPlusParam 5000000 399 ns/op 48 B/op 1 allocs/op
BenchmarkTango_GPlusParam 1000000 2070 ns/op 264 B/op 8 allocs/op
BenchmarkTigerTonic_GPlusParam 500000 4853 ns/op 1056 B/op 17 allocs/op
BenchmarkTraffic_GPlusParam 200000 8278 ns/op 1976 B/op 21 allocs/op
BenchmarkVulcan_GPlusParam 1000000 1243 ns/op 98 B/op 3 allocs/op
BenchmarkAce_GPlus2Params 3000000 549 ns/op 64 B/op 1 allocs/op
BenchmarkBear_GPlus2Params 1000000 2112 ns/op 496 B/op 5 allocs/op
BenchmarkBeego_GPlus2Params 500000 2750 ns/op 368 B/op 4 allocs/op
BenchmarkBone_GPlus2Params 300000 7032 ns/op 1040 B/op 9 allocs/op
BenchmarkDenco_GPlus2Params 3000000 502 ns/op 64 B/op 1 allocs/op
BenchmarkEcho_GPlus2Params 3000000 641 ns/op 32 B/op 1 allocs/op
BenchmarkGin_GPlus2Params 5000000 250 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GPlus2Params 1000000 2681 ns/op 712 B/op 9 allocs/op
BenchmarkGoji_GPlus2Params 1000000 1926 ns/op 336 B/op 2 allocs/op
BenchmarkGojiv2_GPlus2Params 500000 3996 ns/op 1024 B/op 11 allocs/op
BenchmarkGoJsonRest_GPlus2Params 500000 3886 ns/op 713 B/op 14 allocs/op
BenchmarkGoRestful_GPlus2Params 200000 10376 ns/op 2360 B/op 21 allocs/op
BenchmarkGorillaMux_GPlus2Params 100000 14162 ns/op 1088 B/op 11 allocs/op
BenchmarkHttpRouter_GPlus2Params 5000000 336 ns/op 64 B/op 1 allocs/op
BenchmarkHttpTreeMux_GPlus2Params 1000000 1523 ns/op 384 B/op 4 allocs/op
BenchmarkKocha_GPlus2Params 2000000 970 ns/op 128 B/op 5 allocs/op
BenchmarkLARS_GPlus2Params 5000000 238 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_GPlus2Params 500000 4016 ns/op 1056 B/op 10 allocs/op
BenchmarkMartini_GPlus2Params 100000 21253 ns/op 1200 B/op 13 allocs/op
BenchmarkPat_GPlus2Params 200000 8632 ns/op 2256 B/op 34 allocs/op
BenchmarkPossum_GPlus2Params 1000000 2171 ns/op 560 B/op 6 allocs/op
BenchmarkR2router_GPlus2Params 1000000 1340 ns/op 432 B/op 5 allocs/op
BenchmarkRivet_GPlus2Params 3000000 557 ns/op 96 B/op 1 allocs/op
BenchmarkTango_GPlus2Params 1000000 2186 ns/op 344 B/op 8 allocs/op
BenchmarkTigerTonic_GPlus2Params 200000 9060 ns/op 1488 B/op 24 allocs/op
BenchmarkTraffic_GPlus2Params 100000 20324 ns/op 3272 B/op 31 allocs/op
BenchmarkVulcan_GPlus2Params 1000000 2039 ns/op 98 B/op 3 allocs/op
BenchmarkAce_GPlusAll 300000 6603 ns/op 640 B/op 11 allocs/op
BenchmarkBear_GPlusAll 100000 22363 ns/op 5488 B/op 61 allocs/op
BenchmarkBeego_GPlusAll 50000 38757 ns/op 4784 B/op 52 allocs/op
BenchmarkBone_GPlusAll 20000 54916 ns/op 10336 B/op 98 allocs/op
BenchmarkDenco_GPlusAll 300000 4959 ns/op 672 B/op 11 allocs/op
BenchmarkEcho_GPlusAll 200000 6558 ns/op 416 B/op 13 allocs/op
BenchmarkGin_GPlusAll 500000 2757 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_GPlusAll 50000 34615 ns/op 8040 B/op 103 allocs/op
BenchmarkGoji_GPlusAll 100000 16002 ns/op 3696 B/op 22 allocs/op
BenchmarkGojiv2_GPlusAll 50000 35060 ns/op 12624 B/op 115 allocs/op
BenchmarkGoJsonRest_GPlusAll 50000 41479 ns/op 8117 B/op 170 allocs/op
BenchmarkGoRestful_GPlusAll 10000 131653 ns/op 32024 B/op 275 allocs/op
BenchmarkGorillaMux_GPlusAll 10000 101380 ns/op 13296 B/op 142 allocs/op
BenchmarkHttpRouter_GPlusAll 500000 3711 ns/op 640 B/op 11 allocs/op
BenchmarkHttpTreeMux_GPlusAll 100000 14438 ns/op 4032 B/op 38 allocs/op
BenchmarkKocha_GPlusAll 200000 8039 ns/op 976 B/op 43 allocs/op
BenchmarkLARS_GPlusAll 500000 2630 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_GPlusAll 30000 51123 ns/op 13152 B/op 128 allocs/op
BenchmarkMartini_GPlusAll 10000 176157 ns/op 14016 B/op 145 allocs/op
BenchmarkPat_GPlusAll 20000 69911 ns/op 16576 B/op 298 allocs/op
BenchmarkPossum_GPlusAll 100000 20716 ns/op 5408 B/op 39 allocs/op
BenchmarkR2router_GPlusAll 100000 17463 ns/op 5040 B/op 63 allocs/op
BenchmarkRivet_GPlusAll 300000 5142 ns/op 768 B/op 11 allocs/op
BenchmarkTango_GPlusAll 50000 27321 ns/op 3656 B/op 104 allocs/op
BenchmarkTigerTonic_GPlusAll 20000 77597 ns/op 14512 B/op 288 allocs/op
BenchmarkTraffic_GPlusAll 10000 151406 ns/op 37360 B/op 392 allocs/op
BenchmarkVulcan_GPlusAll 100000 18555 ns/op 1274 B/op 39 allocs/op
```
## Parse.com
```
BenchmarkGin_ParseStatic 10000000 133 ns/op 0 B/op 0 allocs/op
BenchmarkAce_ParseStatic 5000000 241 ns/op 0 B/op 0 allocs/op
BenchmarkBear_ParseStatic 2000000 728 ns/op 120 B/op 3 allocs/op
BenchmarkBeego_ParseStatic 1000000 2623 ns/op 368 B/op 4 allocs/op
BenchmarkBone_ParseStatic 1000000 1285 ns/op 144 B/op 3 allocs/op
BenchmarkDenco_ParseStatic 30000000 57.8 ns/op 0 B/op 0 allocs/op
BenchmarkEcho_ParseStatic 5000000 342 ns/op 32 B/op 1 allocs/op
BenchmarkGocraftWeb_ParseStatic 1000000 1478 ns/op 296 B/op 5 allocs/op
BenchmarkGoji_ParseStatic 3000000 415 ns/op 0 B/op 0 allocs/op
BenchmarkGojiv2_ParseStatic 1000000 2087 ns/op 928 B/op 7 allocs/op
BenchmarkGoJsonRest_ParseStatic 1000000 1712 ns/op 329 B/op 11 allocs/op
BenchmarkGoRestful_ParseStatic 200000 11072 ns/op 3224 B/op 22 allocs/op
BenchmarkGorillaMux_ParseStatic 500000 4129 ns/op 752 B/op 11 allocs/op
BenchmarkHttpRouter_ParseStatic 30000000 52.4 ns/op 0 B/op 0 allocs/op
BenchmarkHttpTreeMux_ParseStatic 20000000 109 ns/op 0 B/op 0 allocs/op
BenchmarkKocha_ParseStatic 20000000 81.8 ns/op 0 B/op 0 allocs/op
BenchmarkLARS_ParseStatic 10000000 150 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_ParseStatic 1000000 3288 ns/op 768 B/op 9 allocs/op
BenchmarkMartini_ParseStatic 200000 9110 ns/op 768 B/op 9 allocs/op
BenchmarkPat_ParseStatic 1000000 1135 ns/op 240 B/op 5 allocs/op
BenchmarkPossum_ParseStatic 1000000 1557 ns/op 416 B/op 3 allocs/op
BenchmarkR2router_ParseStatic 2000000 730 ns/op 144 B/op 4 allocs/op
BenchmarkRivet_ParseStatic 10000000 121 ns/op 0 B/op 0 allocs/op
BenchmarkTango_ParseStatic 1000000 1688 ns/op 248 B/op 8 allocs/op
BenchmarkTigerTonic_ParseStatic 3000000 427 ns/op 48 B/op 1 allocs/op
BenchmarkTraffic_ParseStatic 500000 5962 ns/op 1816 B/op 20 allocs/op
BenchmarkVulcan_ParseStatic 2000000 969 ns/op 98 B/op 3 allocs/op
BenchmarkAce_ParseParam 3000000 497 ns/op 64 B/op 1 allocs/op
BenchmarkBear_ParseParam 1000000 1473 ns/op 467 B/op 5 allocs/op
BenchmarkBeego_ParseParam 1000000 2384 ns/op 368 B/op 4 allocs/op
BenchmarkBone_ParseParam 1000000 2513 ns/op 768 B/op 6 allocs/op
BenchmarkDenco_ParseParam 5000000 364 ns/op 64 B/op 1 allocs/op
BenchmarkEcho_ParseParam 5000000 418 ns/op 32 B/op 1 allocs/op
BenchmarkGin_ParseParam 10000000 163 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_ParseParam 1000000 2361 ns/op 664 B/op 8 allocs/op
BenchmarkGoji_ParseParam 1000000 1590 ns/op 336 B/op 2 allocs/op
BenchmarkGojiv2_ParseParam 1000000 2851 ns/op 976 B/op 9 allocs/op
BenchmarkGoJsonRest_ParseParam 1000000 2965 ns/op 649 B/op 13 allocs/op
BenchmarkGoRestful_ParseParam 200000 12207 ns/op 3544 B/op 23 allocs/op
BenchmarkGorillaMux_ParseParam 500000 5187 ns/op 1088 B/op 12 allocs/op
BenchmarkHttpRouter_ParseParam 5000000 275 ns/op 64 B/op 1 allocs/op
BenchmarkHttpTreeMux_ParseParam 1000000 1108 ns/op 352 B/op 3 allocs/op
BenchmarkKocha_ParseParam 3000000 495 ns/op 56 B/op 3 allocs/op
BenchmarkLARS_ParseParam 10000000 192 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_ParseParam 500000 4103 ns/op 1056 B/op 10 allocs/op
BenchmarkMartini_ParseParam 200000 9878 ns/op 1072 B/op 10 allocs/op
BenchmarkPat_ParseParam 500000 3657 ns/op 1120 B/op 17 allocs/op
BenchmarkPossum_ParseParam 1000000 2084 ns/op 560 B/op 6 allocs/op
BenchmarkR2router_ParseParam 1000000 1251 ns/op 432 B/op 5 allocs/op
BenchmarkRivet_ParseParam 5000000 335 ns/op 48 B/op 1 allocs/op
BenchmarkTango_ParseParam 1000000 1854 ns/op 280 B/op 8 allocs/op
BenchmarkTigerTonic_ParseParam 500000 4582 ns/op 1008 B/op 17 allocs/op
BenchmarkTraffic_ParseParam 200000 8125 ns/op 2248 B/op 23 allocs/op
BenchmarkVulcan_ParseParam 1000000 1148 ns/op 98 B/op 3 allocs/op
BenchmarkAce_Parse2Params 3000000 539 ns/op 64 B/op 1 allocs/op
BenchmarkBear_Parse2Params 1000000 1778 ns/op 496 B/op 5 allocs/op
BenchmarkBeego_Parse2Params 1000000 2519 ns/op 368 B/op 4 allocs/op
BenchmarkBone_Parse2Params 1000000 2596 ns/op 720 B/op 5 allocs/op
BenchmarkDenco_Parse2Params 3000000 492 ns/op 64 B/op 1 allocs/op
BenchmarkEcho_Parse2Params 3000000 484 ns/op 32 B/op 1 allocs/op
BenchmarkGin_Parse2Params 10000000 193 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_Parse2Params 1000000 2575 ns/op 712 B/op 9 allocs/op
BenchmarkGoji_Parse2Params 1000000 1373 ns/op 336 B/op 2 allocs/op
BenchmarkGojiv2_Parse2Params 500000 2416 ns/op 960 B/op 8 allocs/op
BenchmarkGoJsonRest_Parse2Params 300000 3452 ns/op 713 B/op 14 allocs/op
BenchmarkGoRestful_Parse2Params 100000 17719 ns/op 6008 B/op 25 allocs/op
BenchmarkGorillaMux_Parse2Params 300000 5102 ns/op 1088 B/op 11 allocs/op
BenchmarkHttpRouter_Parse2Params 5000000 303 ns/op 64 B/op 1 allocs/op
BenchmarkHttpTreeMux_Parse2Params 1000000 1372 ns/op 384 B/op 4 allocs/op
BenchmarkKocha_Parse2Params 2000000 874 ns/op 128 B/op 5 allocs/op
BenchmarkLARS_Parse2Params 10000000 192 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_Parse2Params 500000 3871 ns/op 1056 B/op 10 allocs/op
BenchmarkMartini_Parse2Params 200000 9954 ns/op 1152 B/op 11 allocs/op
BenchmarkPat_Parse2Params 500000 4194 ns/op 832 B/op 17 allocs/op
BenchmarkPossum_Parse2Params 1000000 2121 ns/op 560 B/op 6 allocs/op
BenchmarkR2router_Parse2Params 1000000 1415 ns/op 432 B/op 5 allocs/op
BenchmarkRivet_Parse2Params 3000000 457 ns/op 96 B/op 1 allocs/op
BenchmarkTango_Parse2Params 1000000 1914 ns/op 312 B/op 8 allocs/op
BenchmarkTigerTonic_Parse2Params 300000 6895 ns/op 1408 B/op 24 allocs/op
BenchmarkTraffic_Parse2Params 200000 8317 ns/op 2040 B/op 22 allocs/op
BenchmarkVulcan_Parse2Params 1000000 1274 ns/op 98 B/op 3 allocs/op
BenchmarkAce_ParseAll 200000 10401 ns/op 640 B/op 16 allocs/op
BenchmarkBear_ParseAll 50000 37743 ns/op 8928 B/op 110 allocs/op
BenchmarkBeego_ParseAll 20000 63193 ns/op 9568 B/op 104 allocs/op
BenchmarkBone_ParseAll 20000 61767 ns/op 14160 B/op 131 allocs/op
BenchmarkDenco_ParseAll 300000 7036 ns/op 928 B/op 16 allocs/op
BenchmarkEcho_ParseAll 200000 11824 ns/op 832 B/op 26 allocs/op
BenchmarkGin_ParseAll 300000 4199 ns/op 0 B/op 0 allocs/op
BenchmarkGocraftWeb_ParseAll 30000 51758 ns/op 13728 B/op 181 allocs/op
BenchmarkGoji_ParseAll 50000 29614 ns/op 5376 B/op 32 allocs/op
BenchmarkGojiv2_ParseAll 20000 68676 ns/op 24464 B/op 199 allocs/op
BenchmarkGoJsonRest_ParseAll 20000 76135 ns/op 13866 B/op 321 allocs/op
BenchmarkGoRestful_ParseAll 5000 389487 ns/op 110928 B/op 600 allocs/op
BenchmarkGorillaMux_ParseAll 10000 221250 ns/op 24864 B/op 292 allocs/op
BenchmarkHttpRouter_ParseAll 200000 6444 ns/op 640 B/op 16 allocs/op
BenchmarkHttpTreeMux_ParseAll 50000 30702 ns/op 5728 B/op 51 allocs/op
BenchmarkKocha_ParseAll 200000 13712 ns/op 1112 B/op 54 allocs/op
BenchmarkLARS_ParseAll 300000 6925 ns/op 0 B/op 0 allocs/op
BenchmarkMacaron_ParseAll 20000 96278 ns/op 24576 B/op 250 allocs/op
BenchmarkMartini_ParseAll 5000 271352 ns/op 25072 B/op 253 allocs/op
BenchmarkPat_ParseAll 20000 74941 ns/op 17264 B/op 343 allocs/op
BenchmarkPossum_ParseAll 50000 39947 ns/op 10816 B/op 78 allocs/op
BenchmarkR2router_ParseAll 50000 42479 ns/op 8352 B/op 120 allocs/op
BenchmarkRivet_ParseAll 200000 7726 ns/op 912 B/op 16 allocs/op
BenchmarkTango_ParseAll 30000 50014 ns/op 7168 B/op 208 allocs/op
BenchmarkTigerTonic_ParseAll 10000 106550 ns/op 19728 B/op 379 allocs/op
BenchmarkTraffic_ParseAll 10000 216037 ns/op 57776 B/op 642 allocs/op
BenchmarkVulcan_ParseAll 50000 34379 ns/op 2548 B/op 78 allocs/op
```
gin-1.3.0/CHANGELOG.md 0000664 0000000 0000000 00000024776 13334514714 0014126 0 ustar 00root root 0000000 0000000 # CHANGELOG
### Gin 1.3.0
- [NEW] Add [`func (*Context) QueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.QueryMap), [`func (*Context) GetQueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetQueryMap), [`func (*Context) PostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.PostFormMap) and [`func (*Context) GetPostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetPostFormMap) to support `type map[string]string` as query string or form parameters, see [#1383](https://github.com/gin-gonic/gin/pull/1383)
- [NEW] Add [`func (*Context) AsciiJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.AsciiJSON), see [#1358](https://github.com/gin-gonic/gin/pull/1358)
- [NEW] Add `Pusher()` in [`type ResponseWriter`](https://godoc.org/github.com/gin-gonic/gin#ResponseWriter) for supporting http2 push, see [#1273](https://github.com/gin-gonic/gin/pull/1273)
- [NEW] Add [`func (*Context) DataFromReader`](https://godoc.org/github.com/gin-gonic/gin#Context.DataFromReader) for serving dynamic data, see [#1304](https://github.com/gin-gonic/gin/pull/1304)
- [NEW] Add [`func (*Context) ShouldBindBodyWith`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith) allowing to call binding multiple times, see [#1341](https://github.com/gin-gonic/gin/pull/1341)
- [NEW] Support pointers in form binding, see [#1336](https://github.com/gin-gonic/gin/pull/1336)
- [NEW] Add [`func (*Context) JSONP`](https://godoc.org/github.com/gin-gonic/gin#Context.JSONP), see [#1333](https://github.com/gin-gonic/gin/pull/1333)
- [NEW] Support default value in form binding, see [#1138](https://github.com/gin-gonic/gin/pull/1138)
- [NEW] Expose validator engine in [`type StructValidator`](https://godoc.org/github.com/gin-gonic/gin/binding#StructValidator), see [#1277](https://github.com/gin-gonic/gin/pull/1277)
- [NEW] Add [`func (*Context) ShouldBind`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind), [`func (*Context) ShouldBindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindQuery) and [`func (*Context) ShouldBindJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindJSON), see [#1047](https://github.com/gin-gonic/gin/pull/1047)
- [NEW] Add support for `time.Time` location in form binding, see [#1117](https://github.com/gin-gonic/gin/pull/1117)
- [NEW] Add [`func (*Context) BindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.BindQuery), see [#1029](https://github.com/gin-gonic/gin/pull/1029)
- [NEW] Make [jsonite](https://github.com/json-iterator/go) optional with build tags, see [#1026](https://github.com/gin-gonic/gin/pull/1026)
- [NEW] Show query string in logger, see [#999](https://github.com/gin-gonic/gin/pull/999)
- [NEW] Add [`func (*Context) SecureJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.SecureJSON), see [#987](https://github.com/gin-gonic/gin/pull/987) and [#993](https://github.com/gin-gonic/gin/pull/993)
- [DEPRECATE] `func (*Context) GetCookie` for [`func (*Context) Cookie`](https://godoc.org/github.com/gin-gonic/gin#Context.Cookie)
- [FIX] Don't display color tags if [`func DisableConsoleColor`](https://godoc.org/github.com/gin-gonic/gin#DisableConsoleColor) called, see [#1072](https://github.com/gin-gonic/gin/pull/1072)
- [FIX] Gin Mode `""` when calling [`func Mode`](https://godoc.org/github.com/gin-gonic/gin#Mode) now returns `const DebugMode`, see [#1250](https://github.com/gin-gonic/gin/pull/1250)
- [FIX] `Flush()` now doesn't overwrite `responseWriter` status code, see [#1460](https://github.com/gin-gonic/gin/pull/1460)
### Gin 1.2.0
- [NEW] Switch from godeps to govendor
- [NEW] Add support for Let's Encrypt via gin-gonic/autotls
- [NEW] Improve README examples and add extra at examples folder
- [NEW] Improved support with App Engine
- [NEW] Add custom template delimiters, see #860
- [NEW] Add Template Func Maps, see #962
- [NEW] Add \*context.Handler(), see #928
- [NEW] Add \*context.GetRawData()
- [NEW] Add \*context.GetHeader() (request)
- [NEW] Add \*context.AbortWithStatusJSON() (JSON content type)
- [NEW] Add \*context.Keys type cast helpers
- [NEW] Add \*context.ShouldBindWith()
- [NEW] Add \*context.MustBindWith()
- [NEW] Add \*engine.SetFuncMap()
- [DEPRECATE] On next release: \*context.BindWith(), see #855
- [FIX] Refactor render
- [FIX] Reworked tests
- [FIX] logger now supports cygwin
- [FIX] Use X-Forwarded-For before X-Real-Ip
- [FIX] time.Time binding (#904)
### Gin 1.1.4
- [NEW] Support google appengine for IsTerminal func
### Gin 1.1.3
- [FIX] Reverted Logger: skip ANSI color commands
### Gin 1.1
- [NEW] Implement QueryArray and PostArray methods
- [NEW] Refactor GetQuery and GetPostForm
- [NEW] Add contribution guide
- [FIX] Corrected typos in README
- [FIX] Removed additional Iota
- [FIX] Changed imports to gopkg instead of github in README (#733)
- [FIX] Logger: skip ANSI color commands if output is not a tty
### Gin 1.0rc2 (...)
- [PERFORMANCE] Fast path for writing Content-Type.
- [PERFORMANCE] Much faster 404 routing
- [PERFORMANCE] Allocation optimizations
- [PERFORMANCE] Faster root tree lookup
- [PERFORMANCE] Zero overhead, String() and JSON() rendering.
- [PERFORMANCE] Faster ClientIP parsing
- [PERFORMANCE] Much faster SSE implementation
- [NEW] Benchmarks suite
- [NEW] Bind validation can be disabled and replaced with custom validators.
- [NEW] More flexible HTML render
- [NEW] Multipart and PostForm bindings
- [NEW] Adds method to return all the registered routes
- [NEW] Context.HandlerName() returns the main handler's name
- [NEW] Adds Error.IsType() helper
- [FIX] Binding multipart form
- [FIX] Integration tests
- [FIX] Crash when binding non struct object in Context.
- [FIX] RunTLS() implementation
- [FIX] Logger() unit tests
- [FIX] Adds SetHTMLTemplate() warning
- [FIX] Context.IsAborted()
- [FIX] More unit tests
- [FIX] JSON, XML, HTML renders accept custom content-types
- [FIX] gin.AbortIndex is unexported
- [FIX] Better approach to avoid directory listing in StaticFS()
- [FIX] Context.ClientIP() always returns the IP with trimmed spaces.
- [FIX] Better warning when running in debug mode.
- [FIX] Google App Engine integration. debugPrint does not use os.Stdout
- [FIX] Fixes integer overflow in error type
- [FIX] Error implements the json.Marshaller interface
- [FIX] MIT license in every file
### Gin 1.0rc1 (May 22, 2015)
- [PERFORMANCE] Zero allocation router
- [PERFORMANCE] Faster JSON, XML and text rendering
- [PERFORMANCE] Custom hand optimized HttpRouter for Gin
- [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations
- [NEW] Built-in support for golang.org/x/net/context
- [NEW] Any(path, handler). Create a route that matches any path
- [NEW] Refactored rendering pipeline (faster and static typeded)
- [NEW] Refactored errors API
- [NEW] IndentedJSON() prints pretty JSON
- [NEW] Added gin.DefaultWriter
- [NEW] UNIX socket support
- [NEW] RouterGroup.BasePath is exposed
- [NEW] JSON validation using go-validate-yourself (very powerful options)
- [NEW] Completed suite of unit tests
- [NEW] HTTP streaming with c.Stream()
- [NEW] StaticFile() creates a router for serving just one file.
- [NEW] StaticFS() has an option to disable directory listing.
- [NEW] StaticFS() for serving static files through virtual filesystems
- [NEW] Server-Sent Events native support
- [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler
- [NEW] Added LoggerWithWriter() middleware
- [NEW] Added RecoveryWithWriter() middleware
- [NEW] Added DefaultPostFormValue()
- [NEW] Added DefaultFormValue()
- [NEW] Added DefaultParamValue()
- [FIX] BasicAuth() when using custom realm
- [FIX] Bug when serving static files in nested routing group
- [FIX] Redirect using built-in http.Redirect()
- [FIX] Logger when printing the requested path
- [FIX] Documentation typos
- [FIX] Context.Engine renamed to Context.engine
- [FIX] Better debugging messages
- [FIX] ErrorLogger
- [FIX] Debug HTTP render
- [FIX] Refactored binding and render modules
- [FIX] Refactored Context initialization
- [FIX] Refactored BasicAuth()
- [FIX] NoMethod/NoRoute handlers
- [FIX] Hijacking http
- [FIX] Better support for Google App Engine (using log instead of fmt)
### Gin 0.6 (Mar 9, 2015)
- [NEW] Support multipart/form-data
- [NEW] NoMethod handler
- [NEW] Validate sub structures
- [NEW] Support for HTTP Realm Auth
- [FIX] Unsigned integers in binding
- [FIX] Improve color logger
### Gin 0.5 (Feb 7, 2015)
- [NEW] Content Negotiation
- [FIX] Solved security bug that allow a client to spoof ip
- [FIX] Fix unexported/ignored fields in binding
### Gin 0.4 (Aug 21, 2014)
- [NEW] Development mode
- [NEW] Unit tests
- [NEW] Add Content.Redirect()
- [FIX] Deferring WriteHeader()
- [FIX] Improved documentation for model binding
### Gin 0.3 (Jul 18, 2014)
- [PERFORMANCE] Normal log and error log are printed in the same call.
- [PERFORMANCE] Improve performance of NoRouter()
- [PERFORMANCE] Improve context's memory locality, reduce CPU cache faults.
- [NEW] Flexible rendering API
- [NEW] Add Context.File()
- [NEW] Add shorcut RunTLS() for http.ListenAndServeTLS
- [FIX] Rename NotFound404() to NoRoute()
- [FIX] Errors in context are purged
- [FIX] Adds HEAD method in Static file serving
- [FIX] Refactors Static() file serving
- [FIX] Using keyed initialization to fix app-engine integration
- [FIX] Can't unmarshal JSON array, #63
- [FIX] Renaming Context.Req to Context.Request
- [FIX] Check application/x-www-form-urlencoded when parsing form
### Gin 0.2b (Jul 08, 2014)
- [PERFORMANCE] Using sync.Pool to allocatio/gc overhead
- [NEW] Travis CI integration
- [NEW] Completely new logger
- [NEW] New API for serving static files. gin.Static()
- [NEW] gin.H() can be serialized into XML
- [NEW] Typed errors. Errors can be typed. Internet/external/custom.
- [NEW] Support for Godeps
- [NEW] Travis/Godocs badges in README
- [NEW] New Bind() and BindWith() methods for parsing request body.
- [NEW] Add Content.Copy()
- [NEW] Add context.LastError()
- [NEW] Add shorcut for OPTIONS HTTP method
- [FIX] Tons of README fixes
- [FIX] Header is written before body
- [FIX] BasicAuth() and changes API a little bit
- [FIX] Recovery() middleware only prints panics
- [FIX] Context.Get() does not panic anymore. Use MustGet() instead.
- [FIX] Multiple http.WriteHeader() in NotFound handlers
- [FIX] Engine.Run() panics if http server can't be setted up
- [FIX] Crash when route path doesn't start with '/'
- [FIX] Do not update header when status code is negative
- [FIX] Setting response headers before calling WriteHeader in context.String()
- [FIX] Add MIT license
- [FIX] Changes behaviour of ErrorLogger() and Logger()
gin-1.3.0/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000006223 13334514714 0015077 0 ustar 00root root 0000000 0000000 # Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at teamgingonic@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
gin-1.3.0/CONTRIBUTING.md 0000664 0000000 0000000 00000001157 13334514714 0014532 0 ustar 00root root 0000000 0000000 ## Contributing
- With issues:
- Use the search tool before opening a new issue.
- Please provide source code and commit sha if you found a bug.
- Review existing issues and provide feedback or react to them.
- With pull requests:
- Open your pull request against `master`
- Your pull request should have no more than two commits, if not you should squash them.
- It should pass all tests in the available continuous integrations systems such as TravisCI.
- You should add/modify tests to cover your proposed code changes.
- If your pull request contains a new feature, please document it on the README.
gin-1.3.0/LICENSE 0000664 0000000 0000000 00000002103 13334514714 0013276 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2014 Manuel Martínez-Almeida
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
gin-1.3.0/Makefile 0000664 0000000 0000000 00000002604 13334514714 0013737 0 ustar 00root root 0000000 0000000 GOFMT ?= gofmt "-s"
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
VETPACKAGES ?= $(shell go list ./... | grep -v /vendor/ | grep -v /examples/)
GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*")
all: install
install: deps
govendor sync
.PHONY: test
test:
sh coverage.sh
.PHONY: fmt
fmt:
$(GOFMT) -w $(GOFILES)
.PHONY: fmt-check
fmt-check:
# get all go files and run go fmt on them
@diff=$$($(GOFMT) -d $(GOFILES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
vet:
go vet $(VETPACKAGES)
deps:
@hash govendor > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/kardianos/govendor; \
fi
@hash embedmd > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/campoy/embedmd; \
fi
embedmd:
embedmd -d *.md
.PHONY: lint
lint:
@hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/golang/lint/golint; \
fi
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
.PHONY: misspell-check
misspell-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -error $(GOFILES)
.PHONY: misspell
misspell:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -w $(GOFILES)
gin-1.3.0/README.md 0000664 0000000 0000000 00000131614 13334514714 0013562 0 ustar 00root root 0000000 0000000 # Gin Web Framework
[](https://travis-ci.org/gin-gonic/gin)
[](https://codecov.io/gh/gin-gonic/gin)
[](https://goreportcard.com/report/github.com/gin-gonic/gin)
[](https://godoc.org/github.com/gin-gonic/gin)
[](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sourcegraph.com/github.com/gin-gonic/gin?badge)
[](https://www.codetriage.com/gin-gonic/gin)
Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.

## Contents
- [Installation](#installation)
- [Prerequisite](#prerequisite)
- [Quick start](#quick-start)
- [Benchmarks](#benchmarks)
- [Gin v1.stable](#gin-v1-stable)
- [Build with jsoniter](#build-with-jsoniter)
- [API Examples](#api-examples)
- [Using GET,POST,PUT,PATCH,DELETE and OPTIONS](#using-get-post-put-patch-delete-and-options)
- [Parameters in path](#parameters-in-path)
- [Querystring parameters](#querystring-parameters)
- [Multipart/Urlencoded Form](#multiparturlencoded-form)
- [Another example: query + post form](#another-example-query--post-form)
- [Map as querystring or postform parameters](#map-as-querystring-or-postform-parameters)
- [Upload files](#upload-files)
- [Grouping routes](#grouping-routes)
- [Blank Gin without middleware by default](#blank-gin-without-middleware-by-default)
- [Using middleware](#using-middleware)
- [How to write log file](#how-to-write-log-file)
- [Model binding and validation](#model-binding-and-validation)
- [Custom Validators](#custom-validators)
- [Only Bind Query String](#only-bind-query-string)
- [Bind Query String or Post Data](#bind-query-string-or-post-data)
- [Bind HTML checkboxes](#bind-html-checkboxes)
- [Multipart/Urlencoded binding](#multiparturlencoded-binding)
- [XML, JSON and YAML rendering](#xml-json-and-yaml-rendering)
- [JSONP rendering](#jsonp)
- [Serving static files](#serving-static-files)
- [Serving data from reader](#serving-data-from-reader)
- [HTML rendering](#html-rendering)
- [Multitemplate](#multitemplate)
- [Redirects](#redirects)
- [Custom Middleware](#custom-middleware)
- [Using BasicAuth() middleware](#using-basicauth-middleware)
- [Goroutines inside a middleware](#goroutines-inside-a-middleware)
- [Custom HTTP configuration](#custom-http-configuration)
- [Support Let's Encrypt](#support-lets-encrypt)
- [Run multiple service using Gin](#run-multiple-service-using-gin)
- [Graceful restart or stop](#graceful-restart-or-stop)
- [Build a single binary with templates](#build-a-single-binary-with-templates)
- [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct)
- [Try to bind body into different structs](#try-to-bind-body-into-different-structs)
- [http2 server push](#http2-server-push)
- [Testing](#testing)
- [Users](#users--)
## Installation
To install Gin package, you need to install Go and set your Go workspace first.
1. Download and install it:
```sh
$ go get -u github.com/gin-gonic/gin
```
2. Import it in your code:
```go
import "github.com/gin-gonic/gin"
```
3. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`.
```go
import "net/http"
```
### Use a vendor tool like [Govendor](https://github.com/kardianos/govendor)
1. `go get` govendor
```sh
$ go get github.com/kardianos/govendor
```
2. Create your project folder and `cd` inside
```sh
$ mkdir -p $GOPATH/src/github.com/myusername/project && cd "$_"
```
3. Vendor init your project and add gin
```sh
$ govendor init
$ govendor fetch github.com/gin-gonic/gin@v1.2
```
4. Copy a starting template inside your project
```sh
$ curl https://raw.githubusercontent.com/gin-gonic/gin/master/examples/basic/main.go > main.go
```
5. Run your project
```sh
$ go run main.go
```
## Prerequisite
Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.
## Quick start
```sh
# assume the following codes in example.go file
$ cat example.go
```
```go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
```
```
# run example.go and visit 0.0.0.0:8080/ping on browser
$ go run example.go
```
## Benchmarks
Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter)
[See all benchmarks](/BENCHMARKS.md)
Benchmark name | (1) | (2) | (3) | (4)
--------------------------------------------|-----------:|------------:|-----------:|---------:
**BenchmarkGin_GithubAll** | **30000** | **48375** | **0** | **0**
BenchmarkAce_GithubAll | 10000 | 134059 | 13792 | 167
BenchmarkBear_GithubAll | 5000 | 534445 | 86448 | 943
BenchmarkBeego_GithubAll | 3000 | 592444 | 74705 | 812
BenchmarkBone_GithubAll | 200 | 6957308 | 698784 | 8453
BenchmarkDenco_GithubAll | 10000 | 158819 | 20224 | 167
BenchmarkEcho_GithubAll | 10000 | 154700 | 6496 | 203
BenchmarkGocraftWeb_GithubAll | 3000 | 570806 | 131656 | 1686
BenchmarkGoji_GithubAll | 2000 | 818034 | 56112 | 334
BenchmarkGojiv2_GithubAll | 2000 | 1213973 | 274768 | 3712
BenchmarkGoJsonRest_GithubAll | 2000 | 785796 | 134371 | 2737
BenchmarkGoRestful_GithubAll | 300 | 5238188 | 689672 | 4519
BenchmarkGorillaMux_GithubAll | 100 | 10257726 | 211840 | 2272
BenchmarkHttpRouter_GithubAll | 20000 | 105414 | 13792 | 167
BenchmarkHttpTreeMux_GithubAll | 10000 | 319934 | 65856 | 671
BenchmarkKocha_GithubAll | 10000 | 209442 | 23304 | 843
BenchmarkLARS_GithubAll | 20000 | 62565 | 0 | 0
BenchmarkMacaron_GithubAll | 2000 | 1161270 | 204194 | 2000
BenchmarkMartini_GithubAll | 200 | 9991713 | 226549 | 2325
BenchmarkPat_GithubAll | 200 | 5590793 | 1499568 | 27435
BenchmarkPossum_GithubAll | 10000 | 319768 | 84448 | 609
BenchmarkR2router_GithubAll | 10000 | 305134 | 77328 | 979
BenchmarkRivet_GithubAll | 10000 | 132134 | 16272 | 167
BenchmarkTango_GithubAll | 3000 | 552754 | 63826 | 1618
BenchmarkTigerTonic_GithubAll | 1000 | 1439483 | 239104 | 5374
BenchmarkTraffic_GithubAll | 100 | 11383067 | 2659329 | 21848
BenchmarkVulcan_GithubAll | 5000 | 394253 | 19894 | 609
- (1): Total Repetitions achieved in constant time, higher means more confident result
- (2): Single Repetition Duration (ns/op), lower is better
- (3): Heap Memory (B/op), lower is better
- (4): Average Allocations per Repetition (allocs/op), lower is better
## Gin v1. stable
- [x] Zero allocation router.
- [x] Still the fastest http router and framework. From routing to writing.
- [x] Complete suite of unit tests
- [x] Battle tested
- [x] API frozen, new releases will not break your code.
## Build with [jsoniter](https://github.com/json-iterator/go)
Gin use `encoding/json` as default json package but you can change to [jsoniter](https://github.com/json-iterator/go) by build from other tags.
```sh
$ go build -tags=jsoniter .
```
## API Examples
### Using GET, POST, PUT, PATCH, DELETE and OPTIONS
```go
func main() {
// Disable Console Color
// gin.DisableConsoleColor()
// Creates a gin router with default middleware:
// logger and recovery (crash-free) middleware
router := gin.Default()
router.GET("/someGet", getting)
router.POST("/somePost", posting)
router.PUT("/somePut", putting)
router.DELETE("/someDelete", deleting)
router.PATCH("/somePatch", patching)
router.HEAD("/someHead", head)
router.OPTIONS("/someOptions", options)
// By default it serves on :8080 unless a
// PORT environment variable was defined.
router.Run()
// router.Run(":3000") for a hard coded port
}
```
### Parameters in path
```go
func main() {
router := gin.Default()
// This handler will match /user/john but will not match /user/ or /user
router.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name")
c.String(http.StatusOK, "Hello %s", name)
})
// However, this one will match /user/john/ and also /user/john/send
// If no other routers match /user/john, it will redirect to /user/john/
router.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
message := name + " is " + action
c.String(http.StatusOK, message)
})
router.Run(":8080")
}
```
### Querystring parameters
```go
func main() {
router := gin.Default()
// Query string parameters are parsed using the existing underlying request object.
// The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe
router.GET("/welcome", func(c *gin.Context) {
firstname := c.DefaultQuery("firstname", "Guest")
lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")
c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
})
router.Run(":8080")
}
```
### Multipart/Urlencoded Form
```go
func main() {
router := gin.Default()
router.POST("/form_post", func(c *gin.Context) {
message := c.PostForm("message")
nick := c.DefaultPostForm("nick", "anonymous")
c.JSON(200, gin.H{
"status": "posted",
"message": message,
"nick": nick,
})
})
router.Run(":8080")
}
```
### Another example: query + post form
```
POST /post?id=1234&page=1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
name=manu&message=this_is_great
```
```go
func main() {
router := gin.Default()
router.POST("/post", func(c *gin.Context) {
id := c.Query("id")
page := c.DefaultQuery("page", "0")
name := c.PostForm("name")
message := c.PostForm("message")
fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
})
router.Run(":8080")
}
```
```
id: 1234; page: 1; name: manu; message: this_is_great
```
### Map as querystring or postform parameters
```
POST /post?ids[a]=1234&ids[b]=hello HTTP/1.1
Content-Type: application/x-www-form-urlencoded
names[first]=thinkerou&names[second]=tianou
```
```go
func main() {
router := gin.Default()
router.POST("/post", func(c *gin.Context) {
ids := c.QueryMap("ids")
names := c.PostFormMap("names")
fmt.Printf("ids: %v; names: %v", ids, names)
})
router.Run(":8080")
}
```
```
ids: map[b:hello a:1234], names: map[second:tianou first:thinkerou]
```
### Upload files
#### Single file
References issue [#774](https://github.com/gin-gonic/gin/issues/774) and detail [example code](examples/upload-file/single).
```go
func main() {
router := gin.Default()
// Set a lower memory limit for multipart forms (default is 32 MiB)
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// single file
file, _ := c.FormFile("file")
log.Println(file.Filename)
// Upload the file to specific dst.
// c.SaveUploadedFile(file, dst)
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
})
router.Run(":8080")
}
```
How to `curl`:
```bash
curl -X POST http://localhost:8080/upload \
-F "file=@/Users/appleboy/test.zip" \
-H "Content-Type: multipart/form-data"
```
#### Multiple files
See the detail [example code](examples/upload-file/multiple).
```go
func main() {
router := gin.Default()
// Set a lower memory limit for multipart forms (default is 32 MiB)
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
files := form.File["upload[]"]
for _, file := range files {
log.Println(file.Filename)
// Upload the file to specific dst.
// c.SaveUploadedFile(file, dst)
}
c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
})
router.Run(":8080")
}
```
How to `curl`:
```bash
curl -X POST http://localhost:8080/upload \
-F "upload[]=@/Users/appleboy/test1.zip" \
-F "upload[]=@/Users/appleboy/test2.zip" \
-H "Content-Type: multipart/form-data"
```
### Grouping routes
```go
func main() {
router := gin.Default()
// Simple group: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// Simple group: v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}
router.Run(":8080")
}
```
### Blank Gin without middleware by default
Use
```go
r := gin.New()
```
instead of
```go
// Default With the Logger and Recovery middleware already attached
r := gin.Default()
```
### Using middleware
```go
func main() {
// Creates a router without any middleware by default
r := gin.New()
// Global middleware
// Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release.
// By default gin.DefaultWriter = os.Stdout
r.Use(gin.Logger())
// Recovery middleware recovers from any panics and writes a 500 if there was one.
r.Use(gin.Recovery())
// Per route middleware, you can add as many as you desire.
r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
// Authorization group
// authorized := r.Group("/", AuthRequired())
// exactly the same as:
authorized := r.Group("/")
// per group middleware! in this case we use the custom created
// AuthRequired() middleware just in the "authorized" group.
authorized.Use(AuthRequired())
{
authorized.POST("/login", loginEndpoint)
authorized.POST("/submit", submitEndpoint)
authorized.POST("/read", readEndpoint)
// nested group
testing := authorized.Group("testing")
testing.GET("/analytics", analyticsEndpoint)
}
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
### How to write log file
```go
func main() {
// Disable Console Color, you don't need console color when writing the logs to file.
gin.DisableConsoleColor()
// Logging to a file.
f, _ := os.Create("gin.log")
gin.DefaultWriter = io.MultiWriter(f)
// Use the following code if you need to write the logs to file and console at the same time.
// gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
router := gin.Default()
router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
router.Run(":8080")
}
```
### Model binding and validation
To bind a request body into a type, use model binding. We currently support binding of JSON, XML and standard form values (foo=bar&boo=baz).
Gin uses [**go-playground/validator.v8**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](http://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Baked_In_Validators_and_Tags).
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"`.
Also, Gin provides two sets of methods for binding:
- **Type** - Must bind
- **Methods** - `Bind`, `BindJSON`, `BindQuery`
- **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.
- **Type** - Should bind
- **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindQuery`
- **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.
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`.
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.
```go
// Binding from JSON
type Login struct {
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
func main() {
router := gin.Default()
// Example for binding JSON ({"user": "manu", "password": "123"})
router.POST("/loginJSON", func(c *gin.Context) {
var json Login
if err := c.ShouldBindJSON(&json); err == nil {
if json.User == "manu" && json.Password == "123" {
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
}
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
// Example for binding a HTML form (user=manu&password=123)
router.POST("/loginForm", func(c *gin.Context) {
var form Login
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&form); err == nil {
if form.User == "manu" && form.Password == "123" {
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
}
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
```
**Sample request**
```shell
$ curl -v -X POST \
http://localhost:8080/loginJSON \
-H 'content-type: application/json' \
-d '{ "user": "manu" }'
> POST /loginJSON HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.51.0
> Accept: */*
> content-type: application/json
> Content-Length: 18
>
* upload completely sent off: 18 out of 18 bytes
< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=utf-8
< Date: Fri, 04 Aug 2017 03:51:31 GMT
< Content-Length: 100
<
{"error":"Key: 'Login.Password' Error:Field validation for 'Password' failed on the 'required' tag"}
```
**Skip validate**
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.
### Custom Validators
It is also possible to register custom validators. See the [example code](examples/custom-validation/server.go).
[embedmd]:# (examples/custom-validation/server.go go)
```go
package main
import (
"net/http"
"reflect"
"time"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"gopkg.in/go-playground/validator.v8"
)
type Booking struct {
CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`
}
func bookableDate(
v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
) bool {
if date, ok := field.Interface().(time.Time); ok {
today := time.Now()
if today.Year() > date.Year() || today.YearDay() > date.YearDay() {
return false
}
}
return true
}
func main() {
route := gin.Default()
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("bookabledate", bookableDate)
}
route.GET("/bookable", getBookable)
route.Run(":8085")
}
func getBookable(c *gin.Context) {
var b Booking
if err := c.ShouldBindWith(&b, binding.Query); err == nil {
c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
}
```
```console
$ curl "localhost:8085/bookable?check_in=2018-04-16&check_out=2018-04-17"
{"message":"Booking dates are valid!"}
$ curl "localhost:8085/bookable?check_in=2018-03-08&check_out=2018-03-09"
{"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"}
```
[Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registed this way.
See the [struct-lvl-validation example](examples/struct-lvl-validations) to learn more.
### Only Bind Query String
`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).
```go
package main
import (
"log"
"github.com/gin-gonic/gin"
)
type Person struct {
Name string `form:"name"`
Address string `form:"address"`
}
func main() {
route := gin.Default()
route.Any("/testing", startPage)
route.Run(":8085")
}
func startPage(c *gin.Context) {
var person Person
if c.ShouldBindQuery(&person) == nil {
log.Println("====== Only Bind By Query String ======")
log.Println(person.Name)
log.Println(person.Address)
}
c.String(200, "Success")
}
```
### Bind Query String or Post Data
See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292).
```go
package main
import "log"
import "github.com/gin-gonic/gin"
import "time"
type Person struct {
Name string `form:"name"`
Address string `form:"address"`
Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
}
func main() {
route := gin.Default()
route.GET("/testing", startPage)
route.Run(":8085")
}
func startPage(c *gin.Context) {
var person Person
// If `GET`, only `Form` binding engine (`query`) used.
// If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).
// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48
if c.ShouldBind(&person) == nil {
log.Println(person.Name)
log.Println(person.Address)
log.Println(person.Birthday)
}
c.String(200, "Success")
}
```
Test it with:
```sh
$ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15"
```
### Bind HTML checkboxes
See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092)
main.go
```go
...
type myForm struct {
Colors []string `form:"colors[]"`
}
...
func formHandler(c *gin.Context) {
var fakeForm myForm
c.ShouldBind(&fakeForm)
c.JSON(200, gin.H{"color": fakeForm.Colors})
}
...
```
form.html
```html
Using posts/index.tmpl
{{ end }} ``` templates/users/index.tmpl ```html {{ define "users/index.tmpl" }}Using users/index.tmpl
{{ end }} ``` #### Custom Template renderer You can also use your own html template render ```go import "html/template" func main() { router := gin.Default() html := template.Must(template.ParseFiles("file1", "file2")) router.SetHTMLTemplate(html) router.Run(":8080") } ``` #### Custom Delimiters You may use custom delims ```go r := gin.Default() r.Delims("{[{", "}]}") r.LoadHTMLGlob("/path/to/templates")) ``` #### Custom Template Funcs See the detail [example code](examples/template). main.go ```go import ( "fmt" "html/template" "net/http" "time" "github.com/gin-gonic/gin" ) func formatAsDate(t time.Time) string { year, month, day := t.Date() return fmt.Sprintf("%d%02d/%02d", year, month, day) } func main() { router := gin.Default() router.Delims("{[{", "}]}") router.SetFuncMap(template.FuncMap{ "formatAsDate": formatAsDate, }) router.LoadHTMLFiles("./testdata/template/raw.tmpl") router.GET("/raw", func(c *gin.Context) { c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), }) }) router.Run(":8080") } ``` raw.tmpl ```html Date: {[{.now | formatAsDate}]} ``` Result: ``` Date: 2017/07/01 ``` ### Multitemplate 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`. ### Redirects Issuing a HTTP redirect is easy. Both internal and external locations are supported. ```go r.GET("/test", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "http://www.google.com/") }) ``` Issuing a Router redirect, use `HandleContext` like below. ``` go r.GET("/test", func(c *gin.Context) { c.Request.URL.Path = "/test2" r.HandleContext(c) }) r.GET("/test2", func(c *gin.Context) { c.JSON(200, gin.H{"hello": "world"}) }) ``` ### Custom Middleware ```go func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // Set example variable c.Set("example", "12345") // before request c.Next() // after request latency := time.Since(t) log.Print(latency) // access the status we are sending status := c.Writer.Status() log.Println(status) } } func main() { r := gin.New() r.Use(Logger()) r.GET("/test", func(c *gin.Context) { example := c.MustGet("example").(string) // it would print: "12345" log.Println(example) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` ### Using BasicAuth() middleware ```go // simulate some private data var secrets = gin.H{ "foo": gin.H{"email": "foo@bar.com", "phone": "123433"}, "austin": gin.H{"email": "austin@example.com", "phone": "666"}, "lena": gin.H{"email": "lena@guapa.com", "phone": "523443"}, } func main() { r := gin.Default() // Group using gin.BasicAuth() middleware // gin.Accounts is a shortcut for map[string]string authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{ "foo": "bar", "austin": "1234", "lena": "hello2", "manu": "4321", })) // /admin/secrets endpoint // hit "localhost:8080/admin/secrets authorized.GET("/secrets", func(c *gin.Context) { // get user, it was set by the BasicAuth middleware user := c.MustGet(gin.AuthUserKey).(string) if secret, ok := secrets[user]; ok { c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret}) } else { c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("}) } }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` ### Goroutines inside a middleware 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. ```go func main() { r := gin.Default() r.GET("/long_async", func(c *gin.Context) { // create copy to be used inside the goroutine cCp := c.Copy() go func() { // simulate a long task with time.Sleep(). 5 seconds time.Sleep(5 * time.Second) // note that you are using the copied context "cCp", IMPORTANT log.Println("Done! in path " + cCp.Request.URL.Path) }() }) r.GET("/long_sync", func(c *gin.Context) { // simulate a long task with time.Sleep(). 5 seconds time.Sleep(5 * time.Second) // since we are NOT using a goroutine, we do not have to copy the context log.Println("Done! in path " + c.Request.URL.Path) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` ### Custom HTTP configuration Use `http.ListenAndServe()` directly, like this: ```go func main() { router := gin.Default() http.ListenAndServe(":8080", router) } ``` or ```go func main() { router := gin.Default() s := &http.Server{ Addr: ":8080", Handler: router, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } s.ListenAndServe() } ``` ### Support Let's Encrypt example for 1-line LetsEncrypt HTTPS servers. [embedmd]:# (examples/auto-tls/example1/main.go go) ```go package main import ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) log.Fatal(autotls.Run(r, "example1.com", "example2.com")) } ``` example for custom autocert manager. [embedmd]:# (examples/auto-tls/example2/main.go go) ```go package main import ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" "golang.org/x/crypto/acme/autocert" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"), Cache: autocert.DirCache("/var/www/.cache"), } log.Fatal(autotls.RunWithManager(r, &m)) } ``` ### Run multiple service using Gin See the [question](https://github.com/gin-gonic/gin/issues/346) and try the following example: [embedmd]:# (examples/multiple-service/main.go go) ```go package main import ( "log" "net/http" "time" "github.com/gin-gonic/gin" "golang.org/x/sync/errgroup" ) var ( g errgroup.Group ) func router01() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 01", }, ) }) return e } func router02() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 02", }, ) }) return e } func main() { server01 := &http.Server{ Addr: ":8080", Handler: router01(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } server02 := &http.Server{ Addr: ":8081", Handler: router02(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } g.Go(func() error { return server01.ListenAndServe() }) g.Go(func() error { return server02.ListenAndServe() }) if err := g.Wait(); err != nil { log.Fatal(err) } } ``` ### Graceful restart or stop Do you want to graceful restart or stop your web server? There are some ways this can be done. We can use [fvbock/endless](https://github.com/fvbock/endless) to replace the default `ListenAndServe`. Refer issue [#296](https://github.com/gin-gonic/gin/issues/296) for more details. ```go router := gin.Default() router.GET("/", handler) // [...] endless.ListenAndServe(":4242", router) ``` An alternative to endless: * [manners](https://github.com/braintree/manners): A polite Go HTTP server that shuts down gracefully. * [graceful](https://github.com/tylerb/graceful): Graceful is a Go package enabling graceful shutdown of an http.Handler server. * [grace](https://github.com/facebookgo/grace): Graceful restart & zero downtime deploy for Go servers. If you are using Go 1.8, you may not need to use this library! Consider using http.Server's built-in [Shutdown()](https://golang.org/pkg/net/http/#Server.Shutdown) method for graceful shutdowns. See the full [graceful-shutdown](./examples/graceful-shutdown) example with gin. [embedmd]:# (examples/graceful-shutdown/graceful-shutdown/server.go go) ```go // +build go1.8 package main import ( "context" "log" "net/http" "os" "os/signal" "time" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() router.GET("/", func(c *gin.Context) { time.Sleep(5 * time.Second) c.String(http.StatusOK, "Welcome Gin Server") }) srv := &http.Server{ Addr: ":8080", Handler: router, } go func() { // service connections if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } }() // Wait for interrupt signal to gracefully shutdown the server with // a timeout of 5 seconds. quit := make(chan os.Signal) signal.Notify(quit, os.Interrupt) <-quit log.Println("Shutdown Server ...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } log.Println("Server exiting") } ``` ### Build a single binary with templates You can build a server into a single binary containing templates by using [go-assets][]. [go-assets]: https://github.com/jessevdk/go-assets ```go func main() { r := gin.New() t, err := loadTemplate() if err != nil { panic(err) } r.SetHTMLTemplate(t) r.GET("/", func(c *gin.Context) { c.HTML(http.StatusOK, "/html/index.tmpl",nil) }) r.Run(":8080") } // loadTemplate loads templates embedded by go-assets-builder func loadTemplate() (*template.Template, error) { t := template.New("") for name, file := range Assets.Files { if file.IsDir() || !strings.HasSuffix(name, ".tmpl") { continue } h, err := ioutil.ReadAll(file) if err != nil { return nil, err } t, err = t.New(name).Parse(string(h)) if err != nil { return nil, err } } return t, nil } ``` See a complete example in the `examples/assets-in-binary` directory. ### Bind form-data request with custom struct The follow example using custom struct: ```go type StructA struct { FieldA string `form:"field_a"` } type StructB struct { NestedStruct StructA FieldB string `form:"field_b"` } type StructC struct { NestedStructPointer *StructA FieldC string `form:"field_c"` } type StructD struct { NestedAnonyStruct struct { FieldX string `form:"field_x"` } FieldD string `form:"field_d"` } func GetDataB(c *gin.Context) { var b StructB c.Bind(&b) c.JSON(200, gin.H{ "a": b.NestedStruct, "b": b.FieldB, }) } func GetDataC(c *gin.Context) { var b StructC c.Bind(&b) c.JSON(200, gin.H{ "a": b.NestedStructPointer, "c": b.FieldC, }) } func GetDataD(c *gin.Context) { var b StructD c.Bind(&b) c.JSON(200, gin.H{ "x": b.NestedAnonyStruct, "d": b.FieldD, }) } func main() { r := gin.Default() r.GET("/getb", GetDataB) r.GET("/getc", GetDataC) r.GET("/getd", GetDataD) r.Run() } ``` Using the command `curl` command result: ``` $ curl "http://localhost:8080/getb?field_a=hello&field_b=world" {"a":{"FieldA":"hello"},"b":"world"} $ curl "http://localhost:8080/getc?field_a=hello&field_c=world" {"a":{"FieldA":"hello"},"c":"world"} $ curl "http://localhost:8080/getd?field_x=hello&field_d=world" {"d":"world","x":{"FieldX":"hello"}} ``` **NOTE**: NOT support the follow style struct: ```go type StructX struct { X struct {} `form:"name_x"` // HERE have form } type StructY struct { Y StructX `form:"name_y"` // HERE hava form } type StructZ struct { Z *StructZ `form:"name_z"` // HERE hava form } ``` In a word, only support nested custom struct which have no `form` now. ### Try to bind body into different structs The normal methods for binding request body consumes `c.Request.Body` and they cannot be called multiple times. ```go type formA struct { Foo string `json:"foo" xml:"foo" binding:"required"` } type formB struct { Bar string `json:"bar" xml:"bar" binding:"required"` } func SomeHandler(c *gin.Context) { objA := formA{} objB := formB{} // This c.ShouldBind consumes c.Request.Body and it cannot be reused. if errA := c.ShouldBind(&objA); errA == nil { c.String(http.StatusOK, `the body should be formA`) // Always an error is occurred by this because c.Request.Body is EOF now. } else if errB := c.ShouldBind(&objB); errB == nil { c.String(http.StatusOK, `the body should be formB`) } else { ... } } ``` For this, you can use `c.ShouldBindBodyWith`. ```go func SomeHandler(c *gin.Context) { objA := formA{} objB := formB{} // This reads c.Request.Body and stores the result into the context. if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil { c.String(http.StatusOK, `the body should be formA`) // At this time, it reuses body stored in the context. } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil { c.String(http.StatusOK, `the body should be formB JSON`) // And it can accepts other formats } else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil { c.String(http.StatusOK, `the body should be formB XML`) } else { ... } } ``` * `c.ShouldBindBodyWith` stores body into the context before binding. This has a slight impact to performance, so you should not use this method if you are enough to call binding at once. * This feature is only needed for some formats -- `JSON`, `XML`, `MsgPack`, `ProtoBuf`. For other formats, `Query`, `Form`, `FormPost`, `FormMultipart`, can be called by `c.ShouldBind()` multiple times without any damage to performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)). ### http2 server push http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information. [embedmd]:# (examples/http-pusher/main.go go) ```go package main import ( "html/template" "log" "github.com/gin-gonic/gin" ) var html = template.Must(template.New("https").Parse(`Can you see this? → {{.Bar}}
\n\n" var _Assets3737a75b5254ed1f6d588b40a3449721f9ea86c2 = "\n\nHello, {{.Foo}}
\n\n" // Assets returns go-assets FileSystem var Assets = assets.NewFileSystem(map[string][]string{"/": {"html"}, "/html": {"bar.tmpl", "index.tmpl"}}, map[string]*assets.File{ "/": { Path: "/", FileMode: 0x800001ed, Mtime: time.Unix(1524365738, 1524365738517125470), Data: nil, }, "/html": { Path: "/html", FileMode: 0x800001ed, Mtime: time.Unix(1524365491, 1524365491289799093), Data: nil, }, "/html/bar.tmpl": { Path: "/html/bar.tmpl", FileMode: 0x1a4, Mtime: time.Unix(1524365491, 1524365491289611557), Data: []byte(_Assetsbfa8d115ce0617d89507412d5393a462f8e9b003), }, "/html/index.tmpl": { Path: "/html/index.tmpl", FileMode: 0x1a4, Mtime: time.Unix(1524365491, 1524365491289995821), Data: []byte(_Assets3737a75b5254ed1f6d588b40a3449721f9ea86c2), }}, "") gin-1.3.0/examples/assets-in-binary/html/ 0000775 0000000 0000000 00000000000 13334514714 0020247 5 ustar 00root root 0000000 0000000 gin-1.3.0/examples/assets-in-binary/html/bar.tmpl 0000664 0000000 0000000 00000000107 13334514714 0021707 0 ustar 00root root 0000000 0000000Can you see this? → {{.Bar}}
gin-1.3.0/examples/assets-in-binary/html/index.tmpl 0000664 0000000 0000000 00000000070 13334514714 0022251 0 ustar 00root root 0000000 0000000Hello, {{.Foo}}
gin-1.3.0/examples/assets-in-binary/main.go 0000664 0000000 0000000 00000001474 13334514714 0020564 0 ustar 00root root 0000000 0000000 package main import ( "html/template" "io/ioutil" "net/http" "strings" "github.com/gin-gonic/gin" ) func main() { r := gin.New() t, err := loadTemplate() if err != nil { panic(err) } r.SetHTMLTemplate(t) r.GET("/", func(c *gin.Context) { c.HTML(http.StatusOK, "/html/index.tmpl", gin.H{ "Foo": "World", }) }) r.GET("/bar", func(c *gin.Context) { c.HTML(http.StatusOK, "/html/bar.tmpl", gin.H{ "Bar": "World", }) }) r.Run(":8080") } func loadTemplate() (*template.Template, error) { t := template.New("") for name, file := range Assets.Files { if file.IsDir() || !strings.HasSuffix(name, ".tmpl") { continue } h, err := ioutil.ReadAll(file) if err != nil { return nil, err } t, err = t.New(name).Parse(string(h)) if err != nil { return nil, err } } return t, nil } gin-1.3.0/examples/auto-tls/ 0000775 0000000 0000000 00000000000 13334514714 0015663 5 ustar 00root root 0000000 0000000 gin-1.3.0/examples/auto-tls/example1/ 0000775 0000000 0000000 00000000000 13334514714 0017377 5 ustar 00root root 0000000 0000000 gin-1.3.0/examples/auto-tls/example1/main.go 0000664 0000000 0000000 00000000423 13334514714 0020651 0 ustar 00root root 0000000 0000000 package main import ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) log.Fatal(autotls.Run(r, "example1.com", "example2.com")) } gin-1.3.0/examples/auto-tls/example2/ 0000775 0000000 0000000 00000000000 13334514714 0017400 5 ustar 00root root 0000000 0000000 gin-1.3.0/examples/auto-tls/example2/main.go 0000664 0000000 0000000 00000000737 13334514714 0020662 0 ustar 00root root 0000000 0000000 package main import ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" "golang.org/x/crypto/acme/autocert" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"), Cache: autocert.DirCache("/var/www/.cache"), } log.Fatal(autotls.RunWithManager(r, &m)) } gin-1.3.0/examples/basic/ 0000775 0000000 0000000 00000000000 13334514714 0015174 5 ustar 00root root 0000000 0000000 gin-1.3.0/examples/basic/main.go 0000664 0000000 0000000 00000002464 13334514714 0016455 0 ustar 00root root 0000000 0000000 package main import ( "net/http" "github.com/gin-gonic/gin" ) var DB = make(map[string]string) func setupRouter() *gin.Engine { // Disable Console Color // gin.DisableConsoleColor() r := gin.Default() // Ping test r.GET("/ping", func(c *gin.Context) { c.String(http.StatusOK, "pong") }) // Get user value r.GET("/user/:name", func(c *gin.Context) { user := c.Params.ByName("name") value, ok := DB[user] if ok { c.JSON(http.StatusOK, gin.H{"user": user, "value": value}) } else { c.JSON(http.StatusOK, gin.H{"user": user, "status": "no value"}) } }) // Authorized group (uses gin.BasicAuth() middleware) // Same than: // authorized := r.Group("/") // authorized.Use(gin.BasicAuth(gin.Credentials{ // "foo": "bar", // "manu": "123", //})) authorized := r.Group("/", gin.BasicAuth(gin.Accounts{ "foo": "bar", // user:foo password:bar "manu": "123", // user:manu password:123 })) authorized.POST("admin", func(c *gin.Context) { user := c.MustGet(gin.AuthUserKey).(string) // Parse JSON var json struct { Value string `json:"value" binding:"required"` } if c.Bind(&json) == nil { DB[user] = json.Value c.JSON(http.StatusOK, gin.H{"status": "ok"}) } }) return r } func main() { r := setupRouter() // Listen and Server in 0.0.0.0:8080 r.Run(":8080") } gin-1.3.0/examples/basic/main_test.go 0000664 0000000 0000000 00000000546 13334514714 0017513 0 ustar 00root root 0000000 0000000 package main import ( "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" ) func TestPingRoute(t *testing.T) { router := setupRouter() w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/ping", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "pong", w.Body.String()) } gin-1.3.0/examples/custom-validation/ 0000775 0000000 0000000 00000000000 13334514714 0017555 5 ustar 00root root 0000000 0000000 gin-1.3.0/examples/custom-validation/server.go 0000664 0000000 0000000 00000002331 13334514714 0021411 0 ustar 00root root 0000000 0000000 package main import ( "net/http" "reflect" "time" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "gopkg.in/go-playground/validator.v8" ) type Booking struct { CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"` CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"` } func bookableDate( v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string, ) bool { if date, ok := field.Interface().(time.Time); ok { today := time.Now() if today.Year() > date.Year() || today.YearDay() > date.YearDay() { return false } } return true } func main() { route := gin.Default() if v, ok := binding.Validator.Engine().(*validator.Validate); ok { v.RegisterValidation("bookabledate", bookableDate) } route.GET("/bookable", getBookable) route.Run(":8085") } func getBookable(c *gin.Context) { var b Booking if err := c.ShouldBindWith(&b, binding.Query); err == nil { c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"}) } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } } gin-1.3.0/examples/favicon/ 0000775 0000000 0000000 00000000000 13334514714 0015540 5 ustar 00root root 0000000 0000000 gin-1.3.0/examples/favicon/favicon.ico 0000664 0000000 0000000 00000002176 13334514714 0017667 0 ustar 00root root 0000000 0000000 h ( == DD00++/++,22YYII )) &v!! 33y w A U e& V ' D i ) % b v m 7 ю ֶ @ ވ 2 !!!! @ !!!!!! 00 OO ==w<<<<++ ,11<<==<