diff --git a/.github/README.md b/.github/README.md
index 375399c6..6e3b39dd 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -65,7 +65,7 @@
-
+
@@ -471,15 +471,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -496,6 +497,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ Media
@@ -507,6 +510,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ Contribute
@@ -530,6 +534,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -548,3 +553,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_de.md b/.github/README_de.md
index 657fe1b4..f47f01e1 100644
--- a/.github/README_de.md
+++ b/.github/README_de.md
@@ -65,7 +65,7 @@
-
+
@@ -467,15 +467,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -492,6 +493,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ Medien
@@ -503,6 +506,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ Mitwirken
@@ -526,6 +530,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -541,6 +546,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](https://github.com/gofiber/fiber/graphs/contributors). `Fiber` is free and open-source software licensed under the [MIT License](https://github.com/gofiber/fiber/blob/master/LICENSE). Official logo was created by [Vic Shรณstak](https://github.com/koddr) and distributed under [Creative Commons](https://creativecommons.org/licenses/by-sa/4.0/) license (CC BY-SA 4.0 International).
-**Third-party library licenses**
+**Third-party MIT licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
\ No newline at end of file
diff --git a/.github/README_es.md b/.github/README_es.md
index 8c486441..ab456b0d 100644
--- a/.github/README_es.md
+++ b/.github/README_es.md
@@ -65,7 +65,7 @@
-
+
@@ -467,15 +467,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -492,6 +493,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ Medios
@@ -503,6 +506,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ Contribuir
@@ -526,6 +530,7 @@ Fiber es un proyecto open source que se mantiene a travรฉs de donaciones para pa
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -544,3 +549,4 @@ Copyright (c) 2019-presente [Fenny](https://github.com/fenny) y [contribuyentes]
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_fr.md b/.github/README_fr.md
index 1cb2ccd7..20905b91 100644
--- a/.github/README_fr.md
+++ b/.github/README_fr.md
@@ -65,7 +65,7 @@
-
+
@@ -467,15 +467,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -492,6 +493,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ Media
@@ -503,6 +506,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ Contribuer
@@ -526,6 +530,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -544,3 +549,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_he.md b/.github/README_he.md
index 1598b2eb..aa670025 100644
--- a/.github/README_he.md
+++ b/.github/README_he.md
@@ -66,7 +66,7 @@
-
+
@@ -579,15 +579,16 @@ For an more _maintainable_ middleware _ecosystem_, we've put official [middlewar
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -615,6 +616,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
@@ -630,7 +633,9 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Is switching from Express to Fiber worth it? ๐ค](https://dev.to/koddr/are-sure-what-your-lovely-web-framework-running-so-fast-2jl1) โ _01 Apr 2020_
- [Creating Fast APIs In Go Using Fiber](https://dev.to/jozsefsallai/creating-fast-apis-in-go-using-fiber-59m9) โ _07 Apr 2020_
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
+- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
@@ -672,6 +677,7 @@ Fiber ืืื ืคืจืืืงื ืงืื ืคืชืื ืฉืชืฉืืื ืืฉืืืื ืชืื ืืกืช
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -702,4 +708,5 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**ืจืืฉืืื ืืช ืฉื ืกืคืจืืืช ืฆื ืฉืืืฉื**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_id.md b/.github/README_id.md
index 046c863b..9a8abd5e 100644
--- a/.github/README_id.md
+++ b/.github/README_id.md
@@ -65,7 +65,7 @@
-
+
@@ -469,15 +469,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -494,6 +495,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ Media
@@ -505,6 +508,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ Berkontribusi
@@ -528,6 +532,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -546,3 +551,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_ja.md b/.github/README_ja.md
index 090d5c0e..94c33291 100644
--- a/.github/README_ja.md
+++ b/.github/README_ja.md
@@ -65,7 +65,7 @@
-
+
@@ -471,15 +471,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -496,6 +497,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ ใกใใฃใข
@@ -507,6 +510,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ ่ฒข็ฎใใ
@@ -530,6 +534,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -548,3 +553,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_ko.md b/.github/README_ko.md
index a87c1c7d..1ded80c0 100644
--- a/.github/README_ko.md
+++ b/.github/README_ko.md
@@ -65,7 +65,7 @@
-
+
@@ -471,15 +471,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -496,6 +497,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ ๋ฏธ๋์ด
@@ -507,6 +510,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ ๊ธฐ์ฌ
@@ -530,6 +534,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -548,3 +553,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_nl.md b/.github/README_nl.md
index d2914826..4906c749 100644
--- a/.github/README_nl.md
+++ b/.github/README_nl.md
@@ -65,7 +65,7 @@
-
+
@@ -471,15 +471,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -496,6 +497,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ Media
@@ -507,6 +510,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ Bijdragen
@@ -530,6 +534,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -548,3 +553,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_pt.md b/.github/README_pt.md
index fc842d93..99ca0477 100644
--- a/.github/README_pt.md
+++ b/.github/README_pt.md
@@ -65,7 +65,7 @@
-
+
@@ -467,15 +467,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -492,6 +493,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ Mรญdia
@@ -503,6 +506,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ Contribuindo
@@ -526,6 +530,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -544,3 +549,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_ru.md b/.github/README_ru.md
index 298b93ee..670e12a3 100644
--- a/.github/README_ru.md
+++ b/.github/README_ru.md
@@ -65,7 +65,7 @@
-
+
@@ -469,15 +469,16 @@ func main() {
ะงัะพะฑั ัะพะทะดะฐัั ะฑะพะปะตะต _ะฟะพะดะดะตัะถะธะฒะฐะตะผัั_ middleware _ัะบะพัะธััะตะผั_, ะผั ะฒัะฝะตัะปะธ [middlewares](https://docs.gofiber.io/middleware) ะฒ ะพัะดะตะปัะฝัะต ัะตะฟะพะทะธัะพัะธะธ:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -495,6 +496,8 @@ func main() {
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ ะะตะดะธะฐ
@@ -506,6 +509,7 @@ func main() {
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ ะะพะผะพัั ะฟัะพะตะบัั
@@ -531,6 +535,7 @@ Fiber โ ััะพ ะฟัะพะตะบั ั ะพัะบััััะผ ะธัั
ะพะดะฝัะผ ะบะพะดะพะผ,
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -549,3 +554,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_tr.md b/.github/README_tr.md
index de92f9eb..df801890 100644
--- a/.github/README_tr.md
+++ b/.github/README_tr.md
@@ -65,7 +65,7 @@
-
+
@@ -465,15 +465,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -490,17 +491,21 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ Medya
-- [Welcome to Fiber โ an Express.js styled web framework written in Go with โค๏ธ](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) โ _03 ลubat 2020_
-- [Fiber released v1.7! ๐ What's new and is it still fast, flexible and friendly?](https://dev.to/koddr/fiber-v2-is-out-now-what-s-new-and-is-he-still-fast-flexible-and-friendly-3ipf) โ _21 ลubat 2020_
-- [๐ Fiber v1.8. What's new, updated and re-thinked?](https://dev.to/koddr/fiber-v1-8-what-s-new-updated-and-re-thinked-339h) โ _03 Mart 2020_
-- [Is switching from Express to Fiber worth it? ๐ค](https://dev.to/koddr/are-sure-what-your-lovely-web-framework-running-so-fast-2jl1) โ _01 Nisan 2020_
-- [Creating Fast APIs In Go Using Fiber](https://dev.to/jozsefsallai/creating-fast-apis-in-go-using-fiber-59m9) โ _07 Nisan 2020_
-- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Nisan 2020_
-- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Nisan 2020_
+- [Welcome to Fiber โ an Express.js styled web framework written in Go with โค๏ธ](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) โ _03 Feb 2020_
+- [Fiber released v1.7! ๐ What's new and is it still fast, flexible and friendly?](https://dev.to/koddr/fiber-v2-is-out-now-what-s-new-and-is-he-still-fast-flexible-and-friendly-3ipf) โ _21 Feb 2020_
+- [๐ Fiber v1.8. What's new, updated and re-thinked?](https://dev.to/koddr/fiber-v1-8-what-s-new-updated-and-re-thinked-339h) โ _03 Mar 2020_
+- [Is switching from Express to Fiber worth it? ๐ค](https://dev.to/koddr/are-sure-what-your-lovely-web-framework-running-so-fast-2jl1) โ _01 Apr 2020_
+- [Creating Fast APIs In Go Using Fiber](https://dev.to/jozsefsallai/creating-fast-apis-in-go-using-fiber-59m9) โ _07 Apr 2020_
+- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
+- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ Destek
@@ -523,6 +528,7 @@ Fiber, alan adฤฑ, gitbook, netlify, serverless yer saฤlayฤฑcฤฑsฤฑ giderleri ve
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -541,3 +547,4 @@ Telif (c) 2019-gรผnรผmรผz [Fenny](https://github.com/fenny) ve [Contributors](ht
**3. Parti yazฤฑlฤฑm lisanlarฤฑ**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/.github/README_zh-CN.md b/.github/README_zh-CN.md
index ccccad8f..a2a8c158 100644
--- a/.github/README_zh-CN.md
+++ b/.github/README_zh-CN.md
@@ -65,7 +65,7 @@
-
+
@@ -470,15 +470,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
-- [gofiber/basicauth](https://github.com/gofiber/basicauth)
-- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
+- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
+- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
+- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@@ -495,6 +496,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
+- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
+- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## ๐ฌ ๅชไฝ
@@ -506,6 +509,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [๐บ Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [๐ Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
+- [Fiber v1.9.6 ๐ฅ How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## ๐ ่ดก็ฎ
@@ -529,6 +533,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
|  | [@bihe](https://github.com/bihe) | โ x 3 |
|  | [@justdave](https://github.com/justdave) | โ x 3 |
|  | [@koddr](https://github.com/koddr) | โ x 1 |
+|  | [@lapolinar](https://github.com/lapolinar) | โ x 1 |
|  | [@diegowifi](https://github.com/diegowifi) | โ x 1 |
|  | [@ssimk0](https://github.com/ssimk0) | โ x 1 |
|  | [@raymayemir](https://github.com/raymayemir) | โ x 1 |
@@ -547,3 +552,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
+- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
diff --git a/app.go b/app.go
index 310940cd..d08147b7 100644
--- a/app.go
+++ b/app.go
@@ -25,7 +25,7 @@ import (
)
// Version of current package
-const Version = "1.9.6"
+const Version = "1.9.7"
// Map is a shortcut for map[string]interface{}
type Map map[string]interface{}
@@ -33,8 +33,7 @@ type Map map[string]interface{}
// App denotes the Fiber application.
type App struct {
// Internal fields
- testconn *testConn // Test connection
- routes [][]*Route // Route stack
+ routes [][]*Route // Route stack
// External fields
Settings *Settings // Fiber settings
@@ -144,10 +143,8 @@ func New(settings ...*Settings) *App {
getBytes = getBytesImmutable
}
}
- // Setup test listener
- app.testconn = new(testConn)
- // Setup server
- app.server = app.newServer()
+ // Update fiber server settings with fasthttp server
+ app.updateSettings()
// Return application
return app
}
@@ -353,10 +350,8 @@ func (grp *Group) All(path string, handlers ...func(*Ctx)) *Group {
// Preforkin is not available using app.Serve(ln net.Listener)
// You can pass an optional *tls.Config to enable TLS.
func (app *App) Serve(ln net.Listener, tlsconfig ...*tls.Config) error {
- // Create fasthttp server
- app.mutex.Lock()
- app.server = app.newServer()
- app.mutex.Unlock()
+ // Update fiber server settings
+ app.updateSettings()
// TLS config
if len(tlsconfig) > 0 {
ln = tls.NewListener(ln, tlsconfig[0])
@@ -383,10 +378,8 @@ func (app *App) Listen(address interface{}, tlsconfig ...*tls.Config) error {
if !strings.Contains(addr, ":") {
addr = ":" + addr
}
- // Create fasthttp server
- app.mutex.Lock()
- app.server = app.newServer()
- app.mutex.Unlock()
+ // Update fiber server settings
+ app.updateSettings()
// Setup listener
var ln net.Listener
var err error
@@ -428,14 +421,6 @@ func (app *App) Shutdown() error {
return app.server.Shutdown()
}
-// TestRaw is like Test buf for raw HTTP strings: GET / HTTP/1.1\r\n\r\n
-func (app *App) TestRaw(request string) error {
- if _, err := app.testconn.r.WriteString(request); err != nil {
- return err
- }
- return app.server.ServeConn(app.testconn)
-}
-
// Test is used for internal debugging by passing a *http.Request
// Timeout is optional and defaults to 1s, -1 will disable it completely.
func (app *App) Test(request *http.Request, msTimeout ...int) (*http.Response, error) {
@@ -448,14 +433,18 @@ func (app *App) Test(request *http.Request, msTimeout ...int) (*http.Response, e
if err != nil {
return nil, err
}
+ // Update server settings
+ app.updateSettings()
+ // Create test connection
+ conn := new(testConn)
// Write raw http request
- if _, err = app.testconn.r.Write(dump); err != nil {
+ if _, err = conn.r.Write(dump); err != nil {
return nil, err
}
// Serve conn to server
channel := make(chan error)
go func() {
- channel <- app.server.ServeConn(app.testconn)
+ channel <- app.server.ServeConn(conn)
}()
// Wait for callback
if timeout >= 0 {
@@ -476,7 +465,7 @@ func (app *App) Test(request *http.Request, msTimeout ...int) (*http.Response, e
return nil, err
}
// Read response
- buffer := bufio.NewReader(&app.testconn.w)
+ buffer := bufio.NewReader(&conn.w)
// Convert raw http response to *http.Response
resp, err := http.ReadResponse(buffer, request)
if err != nil {
@@ -535,8 +524,10 @@ func (dl *disableLogger) Printf(format string, args ...interface{}) {
// fmt.Println(fmt.Sprintf(format, args...))
}
-func (app *App) newServer() *fasthttp.Server {
- return &fasthttp.Server{
+func (app *App) updateSettings() {
+ // Create fasthttp server
+ app.mutex.Lock()
+ app.server = &fasthttp.Server{
Handler: app.handler,
Name: app.Settings.ServerHeader,
Concurrency: app.Settings.Concurrency,
@@ -560,4 +551,5 @@ func (app *App) newServer() *fasthttp.Server {
}
},
}
+ app.mutex.Unlock()
}
diff --git a/app_bench_test.go b/app_bench_test.go
index f944de6a..bceb9a66 100644
--- a/app_bench_test.go
+++ b/app_bench_test.go
@@ -3,3 +3,5 @@
// ๐ API Documentation: https://docs.gofiber.io
package fiber
+
+// // go test -v ./... -run=^$ -bench=Benchmark_Ctx_Acce -benchmem -count=3
diff --git a/app_test.go b/app_test.go
index 3ee75051..a6d752c2 100644
--- a/app_test.go
+++ b/app_test.go
@@ -20,23 +20,19 @@ func testStatus200(t *testing.T, app *App, url string, method string) {
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Nested_Params(t *testing.T) {
+func Test_App_Nested_Params(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
- t.Log(c.Route().Path)
c.Status(400).Send("Should move on")
})
app.Get("/test/:param", func(c *Ctx) {
- t.Log(c.Route().Path)
c.Status(400).Send("Should move on")
})
app.Get("/test/:param/test", func(c *Ctx) {
- t.Log(c.Route().Path)
c.Status(400).Send("Should move on")
})
app.Get("/test/:param/test/:param2", func(c *Ctx) {
- t.Log(c.Route().Path)
c.Status(200).Send("Good job")
})
@@ -47,16 +43,27 @@ func Test_Nested_Params(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Raw(t *testing.T) {
+func Test_App_Use_Params(t *testing.T) {
app := New()
- app.Get("/", func(c *Ctx) {
- c.SendString("Hello, World!")
+
+ app.Use("/prefix/:param", func(c *Ctx) {
+ assertEqual(t, "john", c.Params("param"))
})
- app.TestRaw("GET / HTTP/1.1\r\n\r\n")
-}
+ app.Use("/:param/*", func(c *Ctx) {
+ assertEqual(t, "john", c.Params("param"))
+ assertEqual(t, "doe", c.Params("*"))
+ })
-func Test_Order(t *testing.T) {
+ resp, err := app.Test(httptest.NewRequest("GET", "/prefix/john", nil))
+ assertEqual(t, nil, err, "app.Test(req)")
+ assertEqual(t, 200, resp.StatusCode, "Status code")
+
+ resp, err = app.Test(httptest.NewRequest("GET", "/john/doe", nil))
+ assertEqual(t, nil, err, "app.Test(req)")
+ assertEqual(t, 200, resp.StatusCode, "Status code")
+}
+func Test_App_Order(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -83,7 +90,7 @@ func Test_Order(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, "123", string(body))
}
-func Test_Methods(t *testing.T) {
+func Test_App_Methods(t *testing.T) {
var dummyHandler = func(c *Ctx) {}
@@ -124,7 +131,7 @@ func Test_Methods(t *testing.T) {
}
-func Test_New(t *testing.T) {
+func Test_App_New(t *testing.T) {
app := New()
app.Get("/", func(*Ctx) {
@@ -138,14 +145,14 @@ func Test_New(t *testing.T) {
})
}
-func Test_Shutdown(t *testing.T) {
+func Test_App_Shutdown(t *testing.T) {
app := New(&Settings{
DisableStartupMessage: true,
})
_ = app.Shutdown()
}
-func Test_Static(t *testing.T) {
+func Test_App_Static(t *testing.T) {
app := New()
grp := app.Group("/v1")
@@ -179,7 +186,7 @@ func Test_Static(t *testing.T) {
assertEqual(t, false, resp.Header.Get("Content-Length") == "")
}
-func Test_Group(t *testing.T) {
+func Test_App_Group(t *testing.T) {
var dummyHandler = func(c *Ctx) {}
app := New()
@@ -229,7 +236,7 @@ func Test_Group(t *testing.T) {
testStatus200(t, app, "/test/v1/users", "GET")
}
-func Test_Listen(t *testing.T) {
+func Test_App_Listen(t *testing.T) {
app := New(&Settings{
DisableStartupMessage: true,
})
@@ -245,7 +252,7 @@ func Test_Listen(t *testing.T) {
app.Listen("3003")
}
-func Test_Serve(t *testing.T) {
+func Test_App_Serve(t *testing.T) {
app := New(&Settings{
DisableStartupMessage: true,
Prefork: true,
diff --git a/ctx.go b/ctx.go
index 51244414..baaae3c5 100644
--- a/ctx.go
+++ b/ctx.go
@@ -24,6 +24,7 @@ import (
"time"
schema "github.com/gorilla/schema"
+ "github.com/valyala/bytebufferpool"
fasthttp "github.com/valyala/fasthttp"
)
@@ -100,7 +101,7 @@ func ReleaseCtx(ctx *Ctx) {
}
// Accepts checks if the specified extensions or content types are acceptable.
-func (ctx *Ctx) Accepts(offers ...string) (offer string) {
+func (ctx *Ctx) Accepts(offers ...string) string {
if len(offers) == 0 {
return ""
}
@@ -112,11 +113,6 @@ func (ctx *Ctx) Accepts(offers ...string) (offer string) {
specs := strings.Split(h, ",")
for i := range offers {
mimetype := getMIME(offers[i])
- // if mimetype != "" {
- // mimetype = strings.Split(mimetype, ";")[0]
- // } else {
- // mimetype = offer
- // }
for k := range specs {
spec := strings.TrimSpace(specs[k])
if strings.HasPrefix(spec, "*/*") {
@@ -138,80 +134,18 @@ func (ctx *Ctx) Accepts(offers ...string) (offer string) {
}
// AcceptsCharsets checks if the specified charset is acceptable.
-func (ctx *Ctx) AcceptsCharsets(offers ...string) (offer string) {
- if len(offers) == 0 {
- return ""
- }
-
- h := ctx.Get(HeaderAcceptCharset)
- if h == "" {
- return offers[0]
- }
-
- specs := strings.Split(h, ",")
- for i := range offers {
- for k := range specs {
- spec := strings.TrimSpace(specs[k])
- if strings.HasPrefix(spec, "*") {
- return offers[i]
- }
- if strings.HasPrefix(spec, offers[i]) {
- return offers[i]
- }
- }
- }
- return ""
+func (ctx *Ctx) AcceptsCharsets(offers ...string) string {
+ return getOffer(ctx.Get(HeaderAcceptCharset), offers...)
}
// AcceptsEncodings checks if the specified encoding is acceptable.
-func (ctx *Ctx) AcceptsEncodings(offers ...string) (offer string) {
- if len(offers) == 0 {
- return ""
- }
-
- h := ctx.Get(HeaderAcceptEncoding)
- if h == "" {
- return offers[0]
- }
-
- specs := strings.Split(h, ",")
- for i := range offers {
- for k := range specs {
- spec := strings.TrimSpace(specs[k])
- if strings.HasPrefix(spec, "*") {
- return offers[i]
- }
- if strings.HasPrefix(spec, offers[i]) {
- return offers[i]
- }
- }
- }
- return ""
+func (ctx *Ctx) AcceptsEncodings(offers ...string) string {
+ return getOffer(ctx.Get(HeaderAcceptEncoding), offers...)
}
// AcceptsLanguages checks if the specified language is acceptable.
-func (ctx *Ctx) AcceptsLanguages(offers ...string) (offer string) {
- if len(offers) == 0 {
- return ""
- }
- h := ctx.Get(HeaderAcceptLanguage)
- if h == "" {
- return offers[0]
- }
-
- specs := strings.Split(h, ",")
- for i := range offers {
- for k := range specs {
- spec := strings.TrimSpace(specs[k])
- if strings.HasPrefix(spec, "*") {
- return offers[i]
- }
- if strings.HasPrefix(spec, offers[i]) {
- return offers[i]
- }
- }
- }
- return ""
+func (ctx *Ctx) AcceptsLanguages(offers ...string) string {
+ return getOffer(ctx.Get(HeaderAcceptLanguage), offers...)
}
// Append the specified value to the HTTP response header field.
@@ -220,15 +154,17 @@ func (ctx *Ctx) Append(field string, values ...string) {
if len(values) == 0 {
return
}
- h := getString(ctx.Fasthttp.Response.Header.Peek(field))
+ h := ctx.Fasthttp.Response.Header.Peek(field)
for i := range values {
- if h == "" {
- h += values[i]
- } else {
- h += ", " + values[i]
+ var value = getBytes(values[i])
+ if len(h) == 0 {
+ h = append(h, value...)
+ } else if 0 != bytes.Compare(h, value) && !bytes.HasSuffix(h, append([]byte{' '}, value...)) &&
+ !bytes.Contains(h, append(append([]byte{}, value...), ',')) {
+ h = append(append(h, ',', ' '), value...)
}
}
- ctx.Set(field, h)
+ ctx.Fasthttp.Response.Header.SetBytesV(field, h)
}
// Attachment sets the HTTP response Content-Disposition header field to attachment.
@@ -321,7 +257,7 @@ func (ctx *Ctx) ClearCookie(key ...string) {
// Cookie sets a cookie by passing a cookie struct
func (ctx *Ctx) Cookie(cookie *Cookie) {
- fcookie := &fasthttp.Cookie{}
+ fcookie := fasthttp.AcquireCookie()
fcookie.SetKey(cookie.Name)
fcookie.SetValue(cookie.Value)
fcookie.SetPath(cookie.Path)
@@ -346,6 +282,7 @@ func (ctx *Ctx) Cookie(cookie *Cookie) {
fcookie.SetSameSite(fasthttp.CookieSameSiteDisabled)
}
ctx.Fasthttp.Response.Header.SetCookie(fcookie)
+ fasthttp.ReleaseCookie(fcookie)
}
// Cookies is used for getting a cookie value by key
@@ -381,9 +318,13 @@ func (ctx *Ctx) Error() error {
// It uses Accepts to select a proper format.
// If the header is not specified or there is no proper format, text/plain is used.
func (ctx *Ctx) Format(body interface{}) {
- var b string
- accept := ctx.Accepts("html", "json")
+ // Get accepted content type
+ accept := ctx.Accepts("html", "json", "txt", "xml")
+ // Set accepted content type
+ ctx.Type(accept)
+ // Type convert provided body
+ var b string
switch val := body.(type) {
case string:
b = val
@@ -392,14 +333,26 @@ func (ctx *Ctx) Format(body interface{}) {
default:
b = fmt.Sprintf("%v", val)
}
+
+ // Format based on the accept content type
switch accept {
case "html":
ctx.SendString("
" + b + "
")
case "json":
if err := ctx.JSON(body); err != nil {
- // Fix
+ ctx.Send(body) // Fallback
log.Println("Format: error serializing json ", err)
}
+ case "text":
+ ctx.SendString(b)
+ case "xml":
+ raw, err := xml.Marshal(body)
+ if err != nil {
+ ctx.Send(body) // Fallback
+ log.Println("Format: error serializing xml ", err)
+ } else {
+ ctx.SendString(getString(raw))
+ }
default:
ctx.SendString(b)
}
@@ -542,39 +495,48 @@ func (ctx *Ctx) JSON(data interface{}) error {
// By default, the callback name is simply callback.
func (ctx *Ctx) JSONP(data interface{}, callback ...string) error {
raw, err := json.Marshal(&data)
- // Check for errors
+
if err != nil {
return err
}
- str := "callback("
- if len(callback) > 0 {
- str = callback[0] + "("
- }
- str += getString(raw) + ");"
+ var result, cb string
- ctx.Set(HeaderXContentTypeOptions, "nosniff")
+ if len(callback) > 0 {
+ cb = callback[0]
+ } else {
+ cb = "callback"
+ }
+
+ result = cb + "(" + getString(raw) + ");"
+
+ ctx.Fasthttp.Response.Header.Set(HeaderXContentTypeOptions, "nosniff")
ctx.Fasthttp.Response.Header.SetContentType(MIMEApplicationJavaScript)
- ctx.Fasthttp.Response.SetBodyString(str)
+ ctx.Fasthttp.Response.SetBodyString(result)
+
return nil
}
// Links joins the links followed by the property to populate the responseโs Link HTTP header field.
+// #nosec G104
func (ctx *Ctx) Links(link ...string) {
- h := ""
+ if len(link) == 0 {
+ return
+ }
+ bb := bytebufferpool.Get()
for i := range link {
- l := link[i]
if i%2 == 0 {
- h += "<" + l + ">"
+ bb.WriteByte('<')
+ bb.WriteString(link[i])
+ bb.WriteByte('>')
} else {
- h += `; rel="` + l + `",`
+ bb.WriteString(`; rel="`)
+ bb.WriteString(link[i])
+ bb.WriteString(`",`)
}
}
-
- if len(link) > 0 {
- h = strings.TrimSuffix(h, ",")
- ctx.Set(HeaderLink, h)
- }
+ ctx.Fasthttp.Response.Header.Set(HeaderLink, strings.TrimSuffix(bb.String(), ","))
+ bytebufferpool.Put(bb)
}
// Locals makes it possible to pass interface{} values under string keys scoped to the request
@@ -595,7 +557,7 @@ func (ctx *Ctx) Location(path string) {
// Method contains a string corresponding to the HTTP method of the request: GET, POST, PUT and so on.
func (ctx *Ctx) Method(override ...string) string {
if len(override) > 0 {
- ctx.method = override[0]
+ ctx.method = strings.ToUpper(override[0])
}
return ctx.method
}
@@ -627,16 +589,16 @@ func (ctx *Ctx) OriginalURL() string {
// Params is used to get the route parameters.
// Defaults to empty string "", if the param doesn't exist.
-func (ctx *Ctx) Params(key string) (value string) {
- if ctx.route.Params == nil {
- return
- }
+func (ctx *Ctx) Params(key string) string {
for i := range ctx.route.Params {
- if (ctx.route.Params)[i] == key {
+ if len(key) != len(ctx.route.Params[i]) {
+ continue
+ }
+ if ctx.route.Params[i] == key {
return ctx.values[i]
}
}
- return
+ return ""
}
// Path returns the path part of the request URL.
@@ -714,13 +676,12 @@ func (ctx *Ctx) Range(size int) (rangeData Range, err error) {
// Redirect to the URL derived from the specified path, with specified status.
// If status is not specified, status defaults to 302 Found
func (ctx *Ctx) Redirect(path string, status ...int) {
- code := 302
+ ctx.Fasthttp.Response.Header.Set(HeaderLocation, path)
if len(status) > 0 {
- code = status[0]
+ ctx.Fasthttp.Response.SetStatusCode(status[0])
+ } else {
+ ctx.Fasthttp.Response.SetStatusCode(StatusFound)
}
-
- ctx.Set(HeaderLocation, path)
- ctx.Fasthttp.Response.SetStatusCode(code)
}
// Render a template with data and sends a text/html response.
@@ -860,23 +821,7 @@ func (ctx *Ctx) Type(ext string) *Ctx {
// Vary adds the given header field to the Vary response header.
// This will append the header, if not already listed, otherwise leaves it listed in the current location.
func (ctx *Ctx) Vary(fields ...string) {
- if len(fields) == 0 {
- return
- }
- h := strings.ToLower(getString(ctx.Fasthttp.Response.Header.Peek(HeaderVary)))
- for i := range fields {
- fields[i] = strings.ToLower(fields[i])
- if len(h) == 0 {
- h += fields[i]
- } else if !strings.Contains(h, " "+fields[i]) && !strings.Contains(h, fields[i]+"") || !strings.Contains(h, fields[i]+",") {
- // Next developer, it's your job to optimize the following problem
- // Does the header value "Accept" exist in the following header value
- // "Origin, User-Agent, Accept-Encoding"
- // "Accept-Encoding" contains "Accept", false positive
- h += ", " + fields[i]
- }
- }
- ctx.Set(HeaderVary, h)
+ ctx.Append(HeaderVary, fields...)
}
// Write appends any input to the HTTP body response.
@@ -896,5 +841,5 @@ func (ctx *Ctx) Write(bodies ...interface{}) {
// XHR returns a Boolean property, that is true, if the requestโs X-Requested-With header field is XMLHttpRequest,
// indicating that the request was issued by a client library (such as jQuery).
func (ctx *Ctx) XHR() bool {
- return strings.ToLower(ctx.Get(HeaderXRequestedWith)) == "xmlhttprequest"
+ return strings.EqualFold(ctx.Get(HeaderXRequestedWith), "xmlhttprequest")
}
diff --git a/ctx_bench_test.go b/ctx_bench_test.go
index fd1d49d5..ded41e95 100644
--- a/ctx_bench_test.go
+++ b/ctx_bench_test.go
@@ -13,6 +13,8 @@ import (
"github.com/valyala/fasthttp"
)
+// go test -v ./... -run=^$ -bench=Benchmark_Ctx_Params -benchmem -count=3
+
func Benchmark_Ctx_Accepts(b *testing.B) {
c := AcquireCtx(&fasthttp.RequestCtx{})
defer ReleaseCtx(c)
@@ -63,7 +65,7 @@ func Benchmark_Ctx_AcceptsLanguages(b *testing.B) {
var res string
for n := 0; n < b.N; n++ {
- res = c.AcceptsEncodings("fr")
+ res = c.AcceptsLanguages("fr")
}
assertEqual(b, "fr", res)
@@ -185,9 +187,29 @@ func Benchmark_Ctx_FormFile(b *testing.B) {
// TODO
// }
-// func Benchmark_Ctx_Params(b *testing.B) {
-// TODO
-// }
+func Benchmark_Ctx_Params(b *testing.B) {
+ c := AcquireCtx(&fasthttp.RequestCtx{})
+ defer ReleaseCtx(c)
+
+ c.route = &Route{
+ Params: []string{
+ "param1", "param2", "param3", "param4",
+ },
+ }
+ c.values = []string{
+ "john", "doe", "is", "awesome",
+ }
+
+ var res string
+ for n := 0; n < b.N; n++ {
+ res = c.Params("param1")
+ res = c.Params("param2")
+ res = c.Params("param3")
+ res = c.Params("param4")
+ }
+
+ assertEqual(b, "awesome", res)
+}
// func Benchmark_Ctx_Path(b *testing.B) {
// TODO
@@ -217,13 +239,32 @@ func Benchmark_Ctx_FormFile(b *testing.B) {
// TODO
// }
-// func Benchmark_Ctx_Subdomains(b *testing.B) {
-// TODO
-// }
+func Benchmark_Ctx_Subdomains(b *testing.B) {
+ c := AcquireCtx(&fasthttp.RequestCtx{})
+ defer ReleaseCtx(c)
-// func Benchmark_Ctx_Append(b *testing.B) {
-// TODO
-// }
+ c.Fasthttp.Request.SetRequestURI("http://john.doe.google.com")
+
+ var res []string
+ for n := 0; n < b.N; n++ {
+ res = c.Subdomains()
+ }
+
+ assertEqual(b, []string{"john", "doe"}, res)
+}
+
+func Benchmark_Ctx_Append(b *testing.B) {
+ c := AcquireCtx(&fasthttp.RequestCtx{})
+ defer ReleaseCtx(c)
+
+ for n := 0; n < b.N; n++ {
+ c.Append("X-Custom-Header", "Hello")
+ c.Append("X-Custom-Header", "World")
+ c.Append("X-Custom-Header", "Hello")
+ }
+
+ assertEqual(b, "Hello, World", getString(c.Fasthttp.Response.Header.Peek("X-Custom-Header")))
+}
// func Benchmark_Ctx_Attachment(b *testing.B) {
// TODO
@@ -233,9 +274,19 @@ func Benchmark_Ctx_FormFile(b *testing.B) {
// TODO
// }
-// func Benchmark_Ctx_Cookie(b *testing.B) {
-// TODO
-// }
+func Benchmark_Ctx_Cookie(b *testing.B) {
+ c := AcquireCtx(&fasthttp.RequestCtx{})
+ defer ReleaseCtx(c)
+
+ for n := 0; n < b.N; n++ {
+ c.Cookie(&Cookie{
+ Name: "John",
+ Value: "Doe",
+ })
+ }
+
+ assertEqual(b, "John=Doe; path=/", getString(c.Fasthttp.Response.Header.Peek("Set-Cookie")))
+}
// func Benchmark_Ctx_Download(b *testing.B) {
// TODO
@@ -246,12 +297,28 @@ func Benchmark_Ctx_Format(b *testing.B) {
defer ReleaseCtx(c)
c.Fasthttp.Request.Header.Set("Accept", "text/html")
-
for n := 0; n < b.N; n++ {
c.Format("Hello, World!")
}
-
assertEqual(b, "Hello, World!
", string(c.Fasthttp.Response.Body()))
+
+ c.Fasthttp.Request.Header.Set("Accept", "application/json")
+ for n := 0; n < b.N; n++ {
+ c.Format("Hello, World!")
+ }
+ assertEqual(b, `"Hello, World!"`, string(c.Fasthttp.Response.Body()))
+
+ c.Fasthttp.Request.Header.Set("Accept", "text/plain")
+ for n := 0; n < b.N; n++ {
+ c.Format("Hello, World!")
+ }
+ assertEqual(b, `Hello, World!`, string(c.Fasthttp.Response.Body()))
+
+ c.Fasthttp.Request.Header.Set("Accept", "application/xml")
+ for n := 0; n < b.N; n++ {
+ c.Format("Hello, World!")
+ }
+ assertEqual(b, `Hello, World!`, string(c.Fasthttp.Response.Body()))
}
func Benchmark_Ctx_JSON(b *testing.B) {
@@ -319,6 +386,7 @@ func Benchmark_Ctx_Redirect(b *testing.B) {
defer ReleaseCtx(c)
for n := 0; n < b.N; n++ {
+ c.Redirect("http://example.com")
c.Redirect("http://example.com", 301)
}
assertEqual(b, 301, c.Fasthttp.Response.StatusCode())
@@ -335,8 +403,8 @@ func Benchmark_Ctx_Send(b *testing.B) {
defer ReleaseCtx(c)
for n := 0; n < b.N; n++ {
- c.Send([]byte("Hello, World"))
- c.Send("Hello, World")
+ c.Send([]byte("Hello, World"), "Hello, World!", "Hello, World!")
+ c.Send("Hello, World", 50, 30, 20)
c.Send(1337)
}
assertEqual(b, "1337", string(c.Fasthttp.Response.Body()))
@@ -404,7 +472,7 @@ func Benchmark_Ctx_Vary(b *testing.B) {
c.Vary("Origin")
}
- assertEqual(b, "Origin", string(c.Fasthttp.Response.Header.Peek("Vary")))
+ //assertEqual(b, "origin", string(c.Fasthttp.Response.Header.Peek("Vary")))
}
func Benchmark_Ctx_Write(b *testing.B) {
diff --git a/ctx_test.go b/ctx_test.go
index 26330d6c..5958326c 100644
--- a/ctx_test.go
+++ b/ctx_test.go
@@ -20,7 +20,7 @@ import (
"time"
)
-func Test_Accepts(t *testing.T) {
+func Test_Ctx_Accepts(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -36,7 +36,7 @@ func Test_Accepts(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_AcceptsCharsets(t *testing.T) {
+func Test_Ctx_AcceptsCharsets(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -50,7 +50,7 @@ func Test_AcceptsCharsets(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_AcceptsEncodings(t *testing.T) {
+func Test_Ctx_AcceptsEncodings(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -64,7 +64,7 @@ func Test_AcceptsEncodings(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_AcceptsLanguages(t *testing.T) {
+func Test_Ctx_AcceptsLanguages(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -78,7 +78,7 @@ func Test_AcceptsLanguages(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_BaseURL(t *testing.T) {
+func Test_Ctx_BaseURL(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -91,7 +91,7 @@ func Test_BaseURL(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Body(t *testing.T) {
+func Test_Ctx_Body(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@@ -109,7 +109,7 @@ func Test_Body(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_BodyParser(t *testing.T) {
+func Test_Ctx_BodyParser(t *testing.T) {
app := New()
type Demo struct {
@@ -147,7 +147,7 @@ func Test_BodyParser(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Cookies(t *testing.T) {
+func Test_Ctx_Cookies(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -161,7 +161,7 @@ func Test_Cookies(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_FormFile(t *testing.T) {
+func Test_Ctx_FormFile(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@@ -199,7 +199,7 @@ func Test_FormFile(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_FormValue(t *testing.T) {
+func Test_Ctx_FormValue(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@@ -220,7 +220,7 @@ func Test_FormValue(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Fresh(t *testing.T) {
+func Test_Ctx_Fresh(t *testing.T) {
app := New()
// TODO
app.Get("/test", func(c *Ctx) {
@@ -233,7 +233,7 @@ func Test_Fresh(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Get(t *testing.T) {
+func Test_Ctx_Get(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -248,7 +248,7 @@ func Test_Get(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Hostname(t *testing.T) {
+func Test_Ctx_Hostname(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -261,7 +261,7 @@ func Test_Hostname(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_IP(t *testing.T) {
+func Test_Ctx_IP(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -274,7 +274,7 @@ func Test_IP(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_IPs(t *testing.T) {
+func Test_Ctx_IPs(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -289,7 +289,7 @@ func Test_IPs(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-// func Test_Is(t *testing.T) {
+// func Test_Ctx_Is(t *testing.T) {
// app := New()
// app.Get("/test", func(c *Ctx) {
// c.Is(".json")
@@ -309,26 +309,22 @@ func Test_IPs(t *testing.T) {
// t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
// }
// }
-func Test_Locals(t *testing.T) {
+func Test_Ctx_Locals(t *testing.T) {
app := New()
+
app.Use(func(c *Ctx) {
c.Locals("john", "doe")
c.Next()
})
app.Get("/test", func(c *Ctx) {
- expect := "doe"
- result := c.Locals("john")
- if result != expect {
- t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
- }
+ assertEqual(t, "doe", c.Locals("john"))
})
- req := httptest.NewRequest("GET", "/test", nil)
- resp, err := app.Test(req)
+ resp, err := app.Test(httptest.NewRequest("GET", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Method(t *testing.T) {
+func Test_Ctx_Method(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -340,25 +336,20 @@ func Test_Method(t *testing.T) {
app.Put("/test", func(c *Ctx) {
assertEqual(t, "PUT", c.Method())
})
- req := httptest.NewRequest("GET", "/test", nil)
- resp, err := app.Test(req)
+ resp, err := app.Test(httptest.NewRequest("GET", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
- req = httptest.NewRequest("POST", "/test", nil)
-
- resp, err = app.Test(req)
+ resp, err = app.Test(httptest.NewRequest("POST", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
- req = httptest.NewRequest("PUT", "/test", nil)
-
- resp, err = app.Test(req)
+ resp, err = app.Test(httptest.NewRequest("PUT", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_MultipartForm(t *testing.T) {
+func Test_Ctx_MultipartForm(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@@ -381,20 +372,18 @@ func Test_MultipartForm(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_OriginalURL(t *testing.T) {
+func Test_Ctx_OriginalURL(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
assertEqual(t, "http://google.com/test?search=demo", c.OriginalURL())
})
- req := httptest.NewRequest("GET", "http://google.com/test?search=demo", nil)
-
- resp, err := app.Test(req)
+ resp, err := app.Test(httptest.NewRequest("GET", "http://google.com/test?search=demo", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Params(t *testing.T) {
+func Test_Ctx_Params(t *testing.T) {
app := New()
app.Get("/test/:user", func(c *Ctx) {
@@ -408,25 +397,20 @@ func Test_Params(t *testing.T) {
app.Get("/test3/:optional?", func(c *Ctx) {
assertEqual(t, "", c.Params("optional"))
})
- req := httptest.NewRequest("GET", "/test/john", nil)
- resp, err := app.Test(req)
+ resp, err := app.Test(httptest.NewRequest("GET", "/test/john", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
- req = httptest.NewRequest("GET", "/test2/im/a/cookie", nil)
-
- resp, err = app.Test(req)
+ resp, err = app.Test(httptest.NewRequest("GET", "/test2/im/a/cookie", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
- req = httptest.NewRequest("GET", "/test3", nil)
-
- resp, err = app.Test(req)
+ resp, err = app.Test(httptest.NewRequest("GET", "/test3", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Path(t *testing.T) {
+func Test_Ctx_Path(t *testing.T) {
app := New()
app.Get("/test/:user", func(c *Ctx) {
@@ -439,7 +423,7 @@ func Test_Path(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Query(t *testing.T) {
+func Test_Ctx_Query(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -452,7 +436,7 @@ func Test_Query(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Range(t *testing.T) {
+func Test_Ctx_Range(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -470,7 +454,7 @@ func Test_Range(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Route(t *testing.T) {
+func Test_Ctx_Route(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -483,7 +467,7 @@ func Test_Route(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_SaveFile(t *testing.T) {
+func Test_Ctx_SaveFile(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@@ -520,7 +504,7 @@ func Test_SaveFile(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Secure(t *testing.T) {
+func Test_Ctx_Secure(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -543,7 +527,7 @@ func Test_Secure(t *testing.T) {
// assertEqual(t, nil, err, "app.Test(req)")
// assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Stale(t *testing.T) {
+func Test_Ctx_Stale(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -556,7 +540,7 @@ func Test_Stale(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Subdomains(t *testing.T) {
+func Test_Ctx_Subdomains(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -570,21 +554,21 @@ func Test_Subdomains(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
}
-func Test_Append(t *testing.T) {
+func Test_Ctx_Append(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
- c.Append("X-Test", "hel")
- c.Append("X-Test", "lo", "world")
+ c.Append("X-Test", "Hello")
+ c.Append("X-Test", "World")
+ c.Append("X-Test", "Hello", "World")
})
- req := httptest.NewRequest("GET", "/test", nil)
- resp, err := app.Test(req)
+ resp, err := app.Test(httptest.NewRequest("GET", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
- assertEqual(t, "hel, lo, world", resp.Header.Get("X-Test"))
+ assertEqual(t, "Hello, World", resp.Header.Get("X-Test"))
}
-func Test_Attachment(t *testing.T) {
+func Test_Ctx_Attachment(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -600,7 +584,7 @@ func Test_Attachment(t *testing.T) {
assertEqual(t, "image/png", resp.Header.Get("Content-Type"))
}
-func Test_ClearCookie(t *testing.T) {
+func Test_Ctx_ClearCookie(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -627,7 +611,7 @@ func Test_ClearCookie(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, true, strings.Contains(resp.Header.Get("Set-Cookie"), "expires="))
}
-func Test_Cookie(t *testing.T) {
+func Test_Ctx_Cookie(t *testing.T) {
app := New()
expire := time.Now().Add(24 * time.Hour)
@@ -651,7 +635,7 @@ func Test_Cookie(t *testing.T) {
expireDate := "username=jon; expires=" + string(httpdate) + "; path=/"
assertEqual(t, true, strings.Contains(resp.Header.Get("Set-Cookie"), expireDate))
}
-func Test_Download(t *testing.T) {
+func Test_Ctx_Download(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -676,7 +660,7 @@ func Test_Download(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, true, bytes.Equal(expect, body))
}
-func Test_Format(t *testing.T) {
+func Test_Ctx_Format(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -710,7 +694,7 @@ func Test_Format(t *testing.T) {
assertEqual(t, `"Hello, World!"`, string(body))
}
-func Test_JSON(t *testing.T) {
+func Test_Ctx_JSON(t *testing.T) {
app := New()
type SomeStruct struct {
@@ -738,7 +722,7 @@ func Test_JSON(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `{"Name":"Grame","Age":20}`, string(body))
}
-func Test_JSONP(t *testing.T) {
+func Test_Ctx_JSONP(t *testing.T) {
app := New()
type SomeStruct struct {
@@ -766,7 +750,7 @@ func Test_JSONP(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `john({"Name":"Grame","Age":20});`, string(body))
}
-func Test_Links(t *testing.T) {
+func Test_Ctx_Links(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -783,7 +767,7 @@ func Test_Links(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, `; rel="next",; rel="last"`, resp.Header.Get("Link"))
}
-func Test_Location(t *testing.T) {
+func Test_Ctx_Location(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -797,7 +781,7 @@ func Test_Location(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, "http://example.com", resp.Header.Get("Location"))
}
-func Test_Next(t *testing.T) {
+func Test_Ctx_Next(t *testing.T) {
app := New()
app.Use("/", func(c *Ctx) {
@@ -815,7 +799,7 @@ func Test_Next(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, "Works", resp.Header.Get("X-Next-Result"))
}
-func Test_Redirect(t *testing.T) {
+func Test_Ctx_Redirect(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -828,10 +812,10 @@ func Test_Redirect(t *testing.T) {
assertEqual(t, 301, resp.StatusCode, "Status code")
assertEqual(t, "http://example.com", resp.Header.Get("Location"))
}
-func Test_Render(t *testing.T) {
+func Test_Ctx_Render(t *testing.T) {
// TODO
}
-func Test_Send(t *testing.T) {
+func Test_Ctx_Send(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -850,7 +834,7 @@ func Test_Send(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `1337`, string(body))
}
-func Test_SendBytes(t *testing.T) {
+func Test_Ctx_SendBytes(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -867,7 +851,7 @@ func Test_SendBytes(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `Hello, World`, string(body))
}
-func Test_SendStatus(t *testing.T) {
+func Test_Ctx_SendStatus(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -884,7 +868,7 @@ func Test_SendStatus(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `Unsupported Media Type`, string(body))
}
-func Test_SendString(t *testing.T) {
+func Test_Ctx_SendString(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -901,7 +885,7 @@ func Test_SendString(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `Don't crash please`, string(body))
}
-func Test_Set(t *testing.T) {
+func Test_Ctx_Set(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -920,7 +904,7 @@ func Test_Set(t *testing.T) {
assertEqual(t, "2", resp.Header.Get("X-2"))
assertEqual(t, "1337", resp.Header.Get("X-3"))
}
-func Test_Status(t *testing.T) {
+func Test_Ctx_Status(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -937,7 +921,7 @@ func Test_Status(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `Hello, World`, string(body))
}
-func Test_Type(t *testing.T) {
+func Test_Ctx_Type(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -951,7 +935,7 @@ func Test_Type(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, "application/json", resp.Header.Get("Content-Type"))
}
-func Test_Vary(t *testing.T) {
+func Test_Ctx_Vary(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -965,9 +949,9 @@ func Test_Vary(t *testing.T) {
resp, err := app.Test(req)
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
- assertEqual(t, "origin, user-agent, accept-encoding, accept", resp.Header.Get("Vary"))
+ assertEqual(t, "Origin, User-Agent, Accept-Encoding, Accept", resp.Header.Get("Vary"))
}
-func Test_Write(t *testing.T) {
+func Test_Ctx_Write(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@@ -987,7 +971,7 @@ func Test_Write(t *testing.T) {
assertEqual(t, `Hello, World! 123`, string(body))
}
-func Test_XHR(t *testing.T) {
+func Test_Ctx_XHR(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
diff --git a/go.mod b/go.mod
index 9b9c3cff..7b05d315 100644
--- a/go.mod
+++ b/go.mod
@@ -4,5 +4,6 @@ go 1.11
require (
github.com/gorilla/schema v1.1.0
+ github.com/valyala/bytebufferpool v1.0.0
github.com/valyala/fasthttp v1.12.0
)
diff --git a/params.go b/params.go
deleted file mode 100644
index 99086e3c..00000000
--- a/params.go
+++ /dev/null
@@ -1,168 +0,0 @@
-// โก๏ธ Fiber is an Express inspired web framework written in Go with โ๏ธ
-// ๐ Github Repository: https://github.com/gofiber/fiber
-// ๐ API Documentation: https://docs.gofiber.io
-// โ ๏ธ This path parser was based on urlpath by @ucarion (MIT License).
-// ๐ Modified for the Fiber router by @renanbastos93 & @renewerner87
-// ๐ค ucarion/urlpath - renanbastos93/fastpath - renewerner87/fastpath
-
-package fiber
-
-import (
- "strings"
-)
-
-// paramsParser holds the path segments and param names
-type parsedParams struct {
- Segs []paramSeg
- Params []string
-}
-
-// paramsSeg holds the segment metadata
-type paramSeg struct {
- Param string
- Const string
- IsParam bool
- IsOptional bool
- IsLast bool
-}
-
-var paramsDummy = make([]string, 100, 100)
-
-const wildcardParam string = "*"
-
-// New ...
-func parseParams(pattern string) (p parsedParams) {
- var patternCount int
- aPattern := []string{""}
- if pattern != "" {
- aPattern = strings.Split(pattern, "/")[1:] // every route starts with an "/"
- }
- patternCount = len(aPattern)
-
- var out = make([]paramSeg, patternCount)
- var params []string
- var segIndex int
- for i := 0; i < patternCount; i++ {
- partLen := len(aPattern[i])
- if partLen == 0 { // skip empty parts
- continue
- }
- // is parameter ?
- if aPattern[i][0] == '*' || aPattern[i][0] == ':' {
- out[segIndex] = paramSeg{
- Param: paramTrimmer(aPattern[i]),
- IsParam: true,
- IsOptional: aPattern[i] == wildcardParam || aPattern[i][partLen-1] == '?',
- }
- params = append(params, out[segIndex].Param)
- } else {
- // combine const segments
- if segIndex > 0 && out[segIndex-1].IsParam == false {
- segIndex--
- out[segIndex].Const += "/" + aPattern[i]
- // create new const segment
- } else {
- out[segIndex] = paramSeg{
- Const: aPattern[i],
- }
- }
- }
- segIndex++
- }
- if segIndex == 0 {
- segIndex++
- }
- out[segIndex-1].IsLast = true
-
- p = parsedParams{Segs: out[:segIndex:segIndex], Params: params}
- //fmt.Printf("%+v\n", p)
- return
-}
-
-// Match ...
-func (p *parsedParams) matchParams(s string) ([]string, bool) {
- lenKeys := len(p.Params)
- params := paramsDummy[0:lenKeys:lenKeys]
- var i, j, paramsIterator, partLen int
- if len(s) > 0 {
- s = s[1:]
- }
- for index, segment := range p.Segs {
- partLen = len(s)
- // check parameter
- if segment.IsParam {
- // determine parameter length
- if segment.Param == wildcardParam {
- if segment.IsLast {
- i = partLen
- } else {
- // for the expressjs behavior -> "/api/*/:param" - "/api/joker/batman/robin/1" -> "joker/batman/robin", "1"
- i = findCharPos(s, '/', strings.Count(s, "/")-(len(p.Segs)-(index+1))+1)
- }
- } else {
- i = strings.IndexByte(s, '/')
- }
- if i == -1 {
- i = partLen
- }
-
- if false == segment.IsOptional && i == 0 {
- return nil, false
- }
-
- params[paramsIterator] = s[:i]
- paramsIterator++
- } else {
- // check const segment
- i = len(segment.Const)
- if partLen < i || (i == 0 && partLen > 0) || s[:i] != segment.Const || (partLen > i && s[i] != '/') {
- return nil, false
- }
- }
-
- // reduce founded part from the string
- if partLen > 0 {
- j = i + 1
- if segment.IsLast || partLen < j {
- j = i
- }
-
- s = s[j:]
- }
- }
- if len(s) != 0 {
- return nil, false
- }
-
- return params, true
-}
-func paramTrimmer(param string) string {
- start := 0
- end := len(param)
-
- if param[start] != ':' { // is not a param
- return param
- }
- start++
- if param[end-1] == '?' { // is ?
- end--
- }
-
- return param[start:end]
-}
-func findCharPos(s string, char byte, matchCount int) int {
- if matchCount == 0 {
- matchCount = 1
- }
- endPos, pos := 0, 0
- for matchCount > 0 && pos != -1 {
- if pos > 0 {
- s = s[pos+1:]
- endPos++
- }
- pos = strings.IndexByte(s, char)
- endPos += pos
- matchCount--
- }
- return endPos
-}
diff --git a/router.go b/router.go
index 72c553dd..41e43891 100644
--- a/router.go
+++ b/router.go
@@ -61,46 +61,29 @@ func (app *App) nextRoute(ctx *Ctx) {
}
func (r *Route) matchRoute(path string) (match bool, values []string) {
- // Middleware routes allow prefix matches
if r.use {
- // Match any path if wildcard and pass path as param
- if r.star {
- return true, []string{path}
- }
- // Match any path if route equals '/'
- if r.root {
+ if r.root == true || strings.HasPrefix(path, r.Path) {
return true, values
}
- // Middleware matches path prefix
- if strings.HasPrefix(path, r.Path) {
- return true, values
- }
- // No prefix match, and we do not allow params in app.use
- return false, values
+ // Check for a simple path match
+ } else if len(r.Path) == len(path) && r.Path == path {
+ return true, values
+ // Middleware routes allow prefix matches
+ } else if r.root == true && path == "/" {
+ return true, values
}
// '*' wildcard matches any path
- if r.star {
+ if r.star == true {
return true, []string{path}
}
- // Check if a single '/' matches
- if r.root && path == "/" {
- return true, values
- }
// Does this route have parameters
if len(r.Params) > 0 {
- // Do we have a match?
- params, ok := r.parsed.matchParams(path)
- // We have a match!
- if ok {
- return true, params
+ // Match params
+ if values, match = r.parsed.getMatch(path, r.use); match {
+ return
}
}
- // Check for a simple path match
- if len(r.Path) == len(path) && r.Path == path {
- return true, values
- }
-
- // Nothing match
+ // No match
return false, values
}
@@ -153,12 +136,12 @@ func (app *App) registerMethod(method, path string, handlers ...func(*Ctx)) {
}
var isStar = path == "/*"
// Middleware containing only a `/` equals wildcard
- if isUse && path == "/" {
- isStar = true
- }
+ // if isUse && path == "/" {
+ // isStar = true
+ // }
var isRoot = path == "/"
// Route properties
- var isParsed = parseParams(original)
+ var isParsed = getParams(original)
for i := range handlers {
route := &Route{
use: isUse,
@@ -168,7 +151,7 @@ func (app *App) registerMethod(method, path string, handlers ...func(*Ctx)) {
Path: path,
Method: method,
- Params: isParsed.Params,
+ Params: isParsed.params,
Handler: handlers[i],
}
if method == "*" {
diff --git a/router_bench_test.go b/router_bench_test.go
index c83e3dfc..a26d9b38 100644
--- a/router_bench_test.go
+++ b/router_bench_test.go
@@ -4,611 +4,614 @@
package fiber
-// import (
-// "testing"
-// )
+// go test -v ./... -run=^$ -bench=Benchmark_Router -benchmem -count=3
-// var router_bench_app *App
+import (
+ "testing"
+)
-// func init() {
-// router_bench_app = New()
-// h := func(c *Ctx) {}
-// for _, r := range githubAPI {
-// switch r.method {
-// case "GET":
-// router_bench_app.Get(r.path, h)
-// case "POST":
-// router_bench_app.Post(r.path, h)
-// case "PUT":
-// router_bench_app.Put(r.path, h)
-// case "PATCH":
-// router_bench_app.Patch(r.path, h)
-// case "DELETE":
-// router_bench_app.Delete(r.path, h)
-// default:
-// panic("Unknow HTTP method: " + r.method)
-// }
-// }
-// }
+var routerBenchApp *App
-// func Benchmark_Router_Github_Routes(b *testing.B) {
-// var match bool
-// var params []string
-// for n := 0; n < b.N; n++ {
-// for i := range testRoutes {
-// match, params = matchRoute(testRoutes[i].method, testRoutes[i].path)
-// }
-// if match {
-// if len(params) > 0 {
+func init() {
+ routerBenchApp = New()
+ h := func(c *Ctx) {}
+ for _, r := range githubAPI {
+ switch r.method {
+ case "GET":
+ routerBenchApp.Get(r.path, h)
+ case "POST":
+ routerBenchApp.Post(r.path, h)
+ case "PUT":
+ routerBenchApp.Put(r.path, h)
+ case "PATCH":
+ routerBenchApp.Patch(r.path, h)
+ case "DELETE":
+ routerBenchApp.Delete(r.path, h)
+ default:
+ panic("Unknow HTTP method: " + r.method)
+ }
+ }
+ for i := 0; i < 100; i++ {
+ routerBenchApp.Use("/middleware", func(c *Ctx) {
+ c.Next()
+ })
+ }
+}
-// }
-// }
-// }
-// }
+// go test -v ./... -run=^$ -bench=Benchmark_Router_Next_Stack -benchmem -count=3
+func Benchmark_Router_Next_Stack(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _, _ = matchRoute("GET", "/middleware")
+ }
+}
-// func Benchmark_Router_Last_Route(b *testing.B) {
-// var match bool
-// var params []string
-// for n := 0; n < b.N; n++ {
-// match, params = matchRoute("DELETE", "/user/keys/1337")
-// }
-// if match {
-// if len(params) > 0 {
+func Benchmark_Router_Github_API(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ for i := range testRoutes {
+ _, _ = matchRoute(testRoutes[i].method, testRoutes[i].path)
+ }
+ }
+}
-// }
-// }
-// }
-// func Benchmark_Router_First_Route(b *testing.B) {
-// var match bool
-// var params []string
-// for n := 0; n < b.N; n++ {
-// match, params = matchRoute("GET", "/authorizations")
-// }
-// if match {
-// if len(params) > 0 {
+func Benchmark_Router_Stacked_Route(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _, _ = matchRoute("GET", "/orgs/gofiber/public_members/fenny")
+ }
+}
-// }
-// }
-// }
+func Benchmark_Router_Last_Route(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _, _ = matchRoute("DELETE", "/user/keys/1337")
+ }
+}
-// func matchRoute(method, path string) (match bool, values []string) {
-// mINT := methodINT[method]
-// for i := range router_bench_app.routes[mINT] {
-// match, values = router_bench_app.routes[mINT][i].matchRoute(path)
-// if match {
-// return true, values
-// }
-// }
-// return
-// }
+func Benchmark_Router_Middle_Route(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _, _ = matchRoute("GET", "/orgs/gofiber/public_members/fenny")
+ }
+}
-// type testRoute struct {
-// method string
-// path string
-// }
+func Benchmark_Router_First_Route(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _, _ = matchRoute("GET", "/authorizations")
+ }
+}
-// var testRoutes = []testRoute{
-// // OAuth Authorizations
-// {"GET", "/authorizations"},
-// {"GET", "/authorizations/1337"},
-// {"POST", "/authorizations"},
-// {"PUT", "/authorizations/clients/inf1nd873nf8912g9t"},
-// {"PATCH", "/authorizations/1337"},
-// {"DELETE", "/authorizations/1337"},
-// {"GET", "/applications/2nds981mng6azl127y/tokens/sn108hbe1geheibf13f"},
-// {"DELETE", "/applications/2nds981mng6azl127y/tokens"},
-// {"DELETE", "/applications/2nds981mng6azl127y/tokens/sn108hbe1geheibf13f"},
+func matchRoute(method, path string) (match bool, values []string) {
+ mINT := methodINT[method]
+ for i := range routerBenchApp.routes[mINT] {
+ _, _ = routerBenchApp.routes[mINT][i].matchRoute(path)
+ }
+ return
+}
-// // Activity
-// {"GET", "/events"},
-// {"GET", "/repos/fenny/fiber/events"},
-// {"GET", "/networks/fenny/fiber/events"},
-// {"GET", "/orgs/gofiber/events"},
-// {"GET", "/users/fenny/received_events"},
-// {"GET", "/users/fenny/received_events/public"},
-// {"GET", "/users/fenny/events"},
-// {"GET", "/users/fenny/events/public"},
-// {"GET", "/users/fenny/events/orgs/gofiber"},
-// {"GET", "/feeds"},
-// {"GET", "/notifications"},
-// {"GET", "/repos/fenny/fiber/notifications"},
-// {"PUT", "/notifications"},
-// {"PUT", "/repos/fenny/fiber/notifications"},
-// {"GET", "/notifications/threads/1337"},
-// {"PATCH", "/notifications/threads/1337"},
-// {"GET", "/notifications/threads/1337/subscription"},
-// {"PUT", "/notifications/threads/1337/subscription"},
-// {"DELETE", "/notifications/threads/1337/subscription"},
-// {"GET", "/repos/fenny/fiber/stargazers"},
-// {"GET", "/users/fenny/starred"},
-// {"GET", "/user/starred"},
-// {"GET", "/user/starred/fenny/fiber"},
-// {"PUT", "/user/starred/fenny/fiber"},
-// {"DELETE", "/user/starred/fenny/fiber"},
-// {"GET", "/repos/fenny/fiber/subscribers"},
-// {"GET", "/users/fenny/subscriptions"},
-// {"GET", "/user/subscriptions"},
-// {"GET", "/repos/fenny/fiber/subscription"},
-// {"PUT", "/repos/fenny/fiber/subscription"},
-// {"DELETE", "/repos/fenny/fiber/subscription"},
-// {"GET", "/user/subscriptions/fenny/fiber"},
-// {"PUT", "/user/subscriptions/fenny/fiber"},
-// {"DELETE", "/user/subscriptions/fenny/fiber"},
+type testRoute struct {
+ method string
+ path string
+}
-// // Gists
-// {"GET", "/users/fenny/gists"},
-// {"GET", "/gists"},
-// {"GET", "/gists/public"},
-// {"GET", "/gists/starred"},
-// {"GET", "/gists/1337"},
-// {"POST", "/gists"},
-// {"PATCH", "/gists/1337"},
-// {"PUT", "/gists/1337/star"},
-// {"DELETE", "/gists/1337/star"},
-// {"GET", "/gists/1337/star"},
-// {"POST", "/gists/1337/forks"},
-// {"DELETE", "/gists/1337"},
+var testRoutes = []testRoute{
+ // OAuth Authorizations
+ {"GET", "/authorizations"},
+ {"GET", "/authorizations/1337"},
+ {"POST", "/authorizations"},
+ {"PUT", "/authorizations/clients/inf1nd873nf8912g9t"},
+ {"PATCH", "/authorizations/1337"},
+ {"DELETE", "/authorizations/1337"},
+ {"GET", "/applications/2nds981mng6azl127y/tokens/sn108hbe1geheibf13f"},
+ {"DELETE", "/applications/2nds981mng6azl127y/tokens"},
+ {"DELETE", "/applications/2nds981mng6azl127y/tokens/sn108hbe1geheibf13f"},
-// // Git Data
-// {"GET", "/repos/fenny/fiber/git/blobs/v948b24g98ubngw9082bn02giub"},
-// {"POST", "/repos/fenny/fiber/git/blobs"},
-// {"GET", "/repos/fenny/fiber/git/commits/v948b24g98ubngw9082bn02giub"},
-// {"POST", "/repos/fenny/fiber/git/commits"},
-// {"GET", "/repos/fenny/fiber/git/refs/im/a/wildcard"},
-// {"GET", "/repos/fenny/fiber/git/refs"},
-// {"POST", "/repos/fenny/fiber/git/refs"},
-// {"PATCH", "/repos/fenny/fiber/git/refs/im/a/wildcard"},
-// {"DELETE", "/repos/fenny/fiber/git/refs/im/a/wildcard"},
-// {"GET", "/repos/fenny/fiber/git/tags/v948b24g98ubngw9082bn02giub"},
-// {"POST", "/repos/fenny/fiber/git/tags"},
-// {"GET", "/repos/fenny/fiber/git/trees/v948b24g98ubngw9082bn02giub"},
-// {"POST", "/repos/fenny/fiber/git/trees"},
+ // Activity
+ {"GET", "/events"},
+ {"GET", "/repos/fenny/fiber/events"},
+ {"GET", "/networks/fenny/fiber/events"},
+ {"GET", "/orgs/gofiber/events"},
+ {"GET", "/users/fenny/received_events"},
+ {"GET", "/users/fenny/received_events/public"},
+ {"GET", "/users/fenny/events"},
+ {"GET", "/users/fenny/events/public"},
+ {"GET", "/users/fenny/events/orgs/gofiber"},
+ {"GET", "/feeds"},
+ {"GET", "/notifications"},
+ {"GET", "/repos/fenny/fiber/notifications"},
+ {"PUT", "/notifications"},
+ {"PUT", "/repos/fenny/fiber/notifications"},
+ {"GET", "/notifications/threads/1337"},
+ {"PATCH", "/notifications/threads/1337"},
+ {"GET", "/notifications/threads/1337/subscription"},
+ {"PUT", "/notifications/threads/1337/subscription"},
+ {"DELETE", "/notifications/threads/1337/subscription"},
+ {"GET", "/repos/fenny/fiber/stargazers"},
+ {"GET", "/users/fenny/starred"},
+ {"GET", "/user/starred"},
+ {"GET", "/user/starred/fenny/fiber"},
+ {"PUT", "/user/starred/fenny/fiber"},
+ {"DELETE", "/user/starred/fenny/fiber"},
+ {"GET", "/repos/fenny/fiber/subscribers"},
+ {"GET", "/users/fenny/subscriptions"},
+ {"GET", "/user/subscriptions"},
+ {"GET", "/repos/fenny/fiber/subscription"},
+ {"PUT", "/repos/fenny/fiber/subscription"},
+ {"DELETE", "/repos/fenny/fiber/subscription"},
+ {"GET", "/user/subscriptions/fenny/fiber"},
+ {"PUT", "/user/subscriptions/fenny/fiber"},
+ {"DELETE", "/user/subscriptions/fenny/fiber"},
-// // Issues
-// {"GET", "/issues"},
-// {"GET", "/user/issues"},
-// {"GET", "/orgs/gofiber/issues"},
-// {"GET", "/repos/fenny/fiber/issues"},
-// {"GET", "/repos/fenny/fiber/issues/1000"},
-// {"POST", "/repos/fenny/fiber/issues"},
-// {"PATCH", "/repos/fenny/fiber/issues/1000"},
-// {"GET", "/repos/fenny/fiber/assignees"},
-// {"GET", "/repos/fenny/fiber/assignees/nic"},
-// {"GET", "/repos/fenny/fiber/issues/1000/comments"},
-// {"GET", "/repos/fenny/fiber/issues/comments"},
-// {"GET", "/repos/fenny/fiber/issues/comments/1337"},
-// {"POST", "/repos/fenny/fiber/issues/1000/comments"},
-// {"PATCH", "/repos/fenny/fiber/issues/comments/1337"},
-// {"DELETE", "/repos/fenny/fiber/issues/comments/1337"},
-// {"GET", "/repos/fenny/fiber/issues/1000/events"},
-// {"GET", "/repos/fenny/fiber/issues/events"},
-// {"GET", "/repos/fenny/fiber/issues/events/1337"},
-// {"GET", "/repos/fenny/fiber/labels"},
-// {"GET", "/repos/fenny/fiber/labels/john"},
-// {"POST", "/repos/fenny/fiber/labels"},
-// {"PATCH", "/repos/fenny/fiber/labels/john"},
-// {"DELETE", "/repos/fenny/fiber/labels/john"},
-// {"GET", "/repos/fenny/fiber/issues/1000/labels"},
-// {"POST", "/repos/fenny/fiber/issues/1000/labels"},
-// {"DELETE", "/repos/fenny/fiber/issues/1000/labels/john"},
-// {"PUT", "/repos/fenny/fiber/issues/1000/labels"},
-// {"DELETE", "/repos/fenny/fiber/issues/1000/labels"},
-// {"GET", "/repos/fenny/fiber/milestones/1000/labels"},
-// {"GET", "/repos/fenny/fiber/milestones"},
-// {"GET", "/repos/fenny/fiber/milestones/1000"},
-// {"POST", "/repos/fenny/fiber/milestones"},
-// {"PATCH", "/repos/fenny/fiber/milestones/1000"},
-// {"DELETE", "/repos/fenny/fiber/milestones/1000"},
+ // Gists
+ {"GET", "/users/fenny/gists"},
+ {"GET", "/gists"},
+ {"GET", "/gists/public"},
+ {"GET", "/gists/starred"},
+ {"GET", "/gists/1337"},
+ {"POST", "/gists"},
+ {"PATCH", "/gists/1337"},
+ {"PUT", "/gists/1337/star"},
+ {"DELETE", "/gists/1337/star"},
+ {"GET", "/gists/1337/star"},
+ {"POST", "/gists/1337/forks"},
+ {"DELETE", "/gists/1337"},
-// // Miscellaneous
-// {"GET", "/emojis"},
-// {"GET", "/gitignore/templates"},
-// {"GET", "/gitignore/templates/john"},
-// {"POST", "/markdown"},
-// {"POST", "/markdown/raw"},
-// {"GET", "/meta"},
-// {"GET", "/rate_limit"},
+ // Git Data
+ {"GET", "/repos/fenny/fiber/git/blobs/v948b24g98ubngw9082bn02giub"},
+ {"POST", "/repos/fenny/fiber/git/blobs"},
+ {"GET", "/repos/fenny/fiber/git/commits/v948b24g98ubngw9082bn02giub"},
+ {"POST", "/repos/fenny/fiber/git/commits"},
+ {"GET", "/repos/fenny/fiber/git/refs/im/a/wildcard"},
+ {"GET", "/repos/fenny/fiber/git/refs"},
+ {"POST", "/repos/fenny/fiber/git/refs"},
+ {"PATCH", "/repos/fenny/fiber/git/refs/im/a/wildcard"},
+ {"DELETE", "/repos/fenny/fiber/git/refs/im/a/wildcard"},
+ {"GET", "/repos/fenny/fiber/git/tags/v948b24g98ubngw9082bn02giub"},
+ {"POST", "/repos/fenny/fiber/git/tags"},
+ {"GET", "/repos/fenny/fiber/git/trees/v948b24g98ubngw9082bn02giub"},
+ {"POST", "/repos/fenny/fiber/git/trees"},
-// // Organizations
-// {"GET", "/users/fenny/orgs"},
-// {"GET", "/user/orgs"},
-// {"GET", "/orgs/gofiber"},
-// {"PATCH", "/orgs/gofiber"},
-// {"GET", "/orgs/gofiber/members"},
-// {"GET", "/orgs/gofiber/members/fenny"},
-// {"DELETE", "/orgs/gofiber/members/fenny"},
-// {"GET", "/orgs/gofiber/public_members"},
-// {"GET", "/orgs/gofiber/public_members/fenny"},
-// {"PUT", "/orgs/gofiber/public_members/fenny"},
-// {"DELETE", "/orgs/gofiber/public_members/fenny"},
-// {"GET", "/orgs/gofiber/teams"},
-// {"GET", "/teams/1337"},
-// {"POST", "/orgs/gofiber/teams"},
-// {"PATCH", "/teams/1337"},
-// {"DELETE", "/teams/1337"},
-// {"GET", "/teams/1337/members"},
-// {"GET", "/teams/1337/members/fenny"},
-// {"PUT", "/teams/1337/members/fenny"},
-// {"DELETE", "/teams/1337/members/fenny"},
-// {"GET", "/teams/1337/repos"},
-// {"GET", "/teams/1337/repos/fenny/fiber"},
-// {"PUT", "/teams/1337/repos/fenny/fiber"},
-// {"DELETE", "/teams/1337/repos/fenny/fiber"},
-// {"GET", "/user/teams"},
+ // Issues
+ {"GET", "/issues"},
+ {"GET", "/user/issues"},
+ {"GET", "/orgs/gofiber/issues"},
+ {"GET", "/repos/fenny/fiber/issues"},
+ {"GET", "/repos/fenny/fiber/issues/1000"},
+ {"POST", "/repos/fenny/fiber/issues"},
+ {"PATCH", "/repos/fenny/fiber/issues/1000"},
+ {"GET", "/repos/fenny/fiber/assignees"},
+ {"GET", "/repos/fenny/fiber/assignees/nic"},
+ {"GET", "/repos/fenny/fiber/issues/1000/comments"},
+ {"GET", "/repos/fenny/fiber/issues/comments"},
+ {"GET", "/repos/fenny/fiber/issues/comments/1337"},
+ {"POST", "/repos/fenny/fiber/issues/1000/comments"},
+ {"PATCH", "/repos/fenny/fiber/issues/comments/1337"},
+ {"DELETE", "/repos/fenny/fiber/issues/comments/1337"},
+ {"GET", "/repos/fenny/fiber/issues/1000/events"},
+ {"GET", "/repos/fenny/fiber/issues/events"},
+ {"GET", "/repos/fenny/fiber/issues/events/1337"},
+ {"GET", "/repos/fenny/fiber/labels"},
+ {"GET", "/repos/fenny/fiber/labels/john"},
+ {"POST", "/repos/fenny/fiber/labels"},
+ {"PATCH", "/repos/fenny/fiber/labels/john"},
+ {"DELETE", "/repos/fenny/fiber/labels/john"},
+ {"GET", "/repos/fenny/fiber/issues/1000/labels"},
+ {"POST", "/repos/fenny/fiber/issues/1000/labels"},
+ {"DELETE", "/repos/fenny/fiber/issues/1000/labels/john"},
+ {"PUT", "/repos/fenny/fiber/issues/1000/labels"},
+ {"DELETE", "/repos/fenny/fiber/issues/1000/labels"},
+ {"GET", "/repos/fenny/fiber/milestones/1000/labels"},
+ {"GET", "/repos/fenny/fiber/milestones"},
+ {"GET", "/repos/fenny/fiber/milestones/1000"},
+ {"POST", "/repos/fenny/fiber/milestones"},
+ {"PATCH", "/repos/fenny/fiber/milestones/1000"},
+ {"DELETE", "/repos/fenny/fiber/milestones/1000"},
-// // Pull Requests
-// {"GET", "/repos/fenny/fiber/pulls"},
-// {"GET", "/repos/fenny/fiber/pulls/1000"},
-// {"POST", "/repos/fenny/fiber/pulls"},
-// {"PATCH", "/repos/fenny/fiber/pulls/1000"},
-// {"GET", "/repos/fenny/fiber/pulls/1000/commits"},
-// {"GET", "/repos/fenny/fiber/pulls/1000/files"},
-// {"GET", "/repos/fenny/fiber/pulls/1000/merge"},
-// {"PUT", "/repos/fenny/fiber/pulls/1000/merge"},
-// {"GET", "/repos/fenny/fiber/pulls/1000/comments"},
-// {"GET", "/repos/fenny/fiber/pulls/comments"},
-// {"GET", "/repos/fenny/fiber/pulls/comments/1000"},
-// {"PUT", "/repos/fenny/fiber/pulls/1000/comments"},
-// {"PATCH", "/repos/fenny/fiber/pulls/comments/1000"},
-// {"DELETE", "/repos/fenny/fiber/pulls/comments/1000"},
+ // Miscellaneous
+ {"GET", "/emojis"},
+ {"GET", "/gitignore/templates"},
+ {"GET", "/gitignore/templates/john"},
+ {"POST", "/markdown"},
+ {"POST", "/markdown/raw"},
+ {"GET", "/meta"},
+ {"GET", "/rate_limit"},
-// // Repositories
-// {"GET", "/user/repos"},
-// {"GET", "/users/fenny/repos"},
-// {"GET", "/orgs/gofiber/repos"},
-// {"GET", "/repositories"},
-// {"POST", "/user/repos"},
-// {"POST", "/orgs/gofiber/repos"},
-// {"GET", "/repos/fenny/fiber"},
-// {"PATCH", "/repos/fenny/fiber"},
-// {"GET", "/repos/fenny/fiber/contributors"},
-// {"GET", "/repos/fenny/fiber/languages"},
-// {"GET", "/repos/fenny/fiber/teams"},
-// {"GET", "/repos/fenny/fiber/tags"},
-// {"GET", "/repos/fenny/fiber/branches"},
-// {"GET", "/repos/fenny/fiber/branches/master"},
-// {"DELETE", "/repos/fenny/fiber"},
-// {"GET", "/repos/fenny/fiber/collaborators"},
-// {"GET", "/repos/fenny/fiber/collaborators/fenny"},
-// {"PUT", "/repos/fenny/fiber/collaborators/fenny"},
-// {"DELETE", "/repos/fenny/fiber/collaborators/fenny"},
-// {"GET", "/repos/fenny/fiber/comments"},
-// {"GET", "/repos/fenny/fiber/commits/v948b24g98ubngw9082bn02giub/comments"},
-// {"POST", "/repos/fenny/fiber/commits/v948b24g98ubngw9082bn02giub/comments"},
-// {"GET", "/repos/fenny/fiber/comments/1337"},
-// {"PATCH", "/repos/fenny/fiber/comments/1337"},
-// {"DELETE", "/repos/fenny/fiber/comments/1337"},
-// {"GET", "/repos/fenny/fiber/commits"},
-// {"GET", "/repos/fenny/fiber/commits/v948b24g98ubngw9082bn02giub"},
-// {"GET", "/repos/fenny/fiber/readme"},
-// {"GET", "/repos/fenny/fiber/contents/im/a/wildcard"},
-// {"PUT", "/repos/fenny/fiber/contents/im/a/wildcard"},
-// {"DELETE", "/repos/fenny/fiber/contents/im/a/wildcard"},
-// {"GET", "/repos/fenny/fiber/gzip/google"},
-// {"GET", "/repos/fenny/fiber/keys"},
-// {"GET", "/repos/fenny/fiber/keys/1337"},
-// {"POST", "/repos/fenny/fiber/keys"},
-// {"PATCH", "/repos/fenny/fiber/keys/1337"},
-// {"DELETE", "/repos/fenny/fiber/keys/1337"},
-// {"GET", "/repos/fenny/fiber/downloads"},
-// {"GET", "/repos/fenny/fiber/downloads/1337"},
-// {"DELETE", "/repos/fenny/fiber/downloads/1337"},
-// {"GET", "/repos/fenny/fiber/forks"},
-// {"POST", "/repos/fenny/fiber/forks"},
-// {"GET", "/repos/fenny/fiber/hooks"},
-// {"GET", "/repos/fenny/fiber/hooks/1337"},
-// {"POST", "/repos/fenny/fiber/hooks"},
-// {"PATCH", "/repos/fenny/fiber/hooks/1337"},
-// {"POST", "/repos/fenny/fiber/hooks/1337/tests"},
-// {"DELETE", "/repos/fenny/fiber/hooks/1337"},
-// {"POST", "/repos/fenny/fiber/merges"},
-// {"GET", "/repos/fenny/fiber/releases"},
-// {"GET", "/repos/fenny/fiber/releases/1337"},
-// {"POST", "/repos/fenny/fiber/releases"},
-// {"PATCH", "/repos/fenny/fiber/releases/1337"},
-// {"DELETE", "/repos/fenny/fiber/releases/1337"},
-// {"GET", "/repos/fenny/fiber/releases/1337/assets"},
-// {"GET", "/repos/fenny/fiber/stats/contributors"},
-// {"GET", "/repos/fenny/fiber/stats/commit_activity"},
-// {"GET", "/repos/fenny/fiber/stats/code_frequency"},
-// {"GET", "/repos/fenny/fiber/stats/participation"},
-// {"GET", "/repos/fenny/fiber/stats/punch_card"},
-// {"GET", "/repos/fenny/fiber/statuses/google"},
-// {"POST", "/repos/fenny/fiber/statuses/google"},
+ // Organizations
+ {"GET", "/users/fenny/orgs"},
+ {"GET", "/user/orgs"},
+ {"GET", "/orgs/gofiber"},
+ {"PATCH", "/orgs/gofiber"},
+ {"GET", "/orgs/gofiber/members"},
+ {"GET", "/orgs/gofiber/members/fenny"},
+ {"DELETE", "/orgs/gofiber/members/fenny"},
+ {"GET", "/orgs/gofiber/public_members"},
+ {"GET", "/orgs/gofiber/public_members/fenny"},
+ {"PUT", "/orgs/gofiber/public_members/fenny"},
+ {"DELETE", "/orgs/gofiber/public_members/fenny"},
+ {"GET", "/orgs/gofiber/teams"},
+ {"GET", "/teams/1337"},
+ {"POST", "/orgs/gofiber/teams"},
+ {"PATCH", "/teams/1337"},
+ {"DELETE", "/teams/1337"},
+ {"GET", "/teams/1337/members"},
+ {"GET", "/teams/1337/members/fenny"},
+ {"PUT", "/teams/1337/members/fenny"},
+ {"DELETE", "/teams/1337/members/fenny"},
+ {"GET", "/teams/1337/repos"},
+ {"GET", "/teams/1337/repos/fenny/fiber"},
+ {"PUT", "/teams/1337/repos/fenny/fiber"},
+ {"DELETE", "/teams/1337/repos/fenny/fiber"},
+ {"GET", "/user/teams"},
-// // Search
-// {"GET", "/search/repositories"},
-// {"GET", "/search/code"},
-// {"GET", "/search/issues"},
-// {"GET", "/search/users"},
-// {"GET", "/legacy/issues/search/fenny/fibersitory/locked/finish"},
-// {"GET", "/legacy/repos/search/finish"},
-// {"GET", "/legacy/user/search/finish"},
-// {"GET", "/legacy/user/email/info@gofiber.io"},
+ // Pull Requests
+ {"GET", "/repos/fenny/fiber/pulls"},
+ {"GET", "/repos/fenny/fiber/pulls/1000"},
+ {"POST", "/repos/fenny/fiber/pulls"},
+ {"PATCH", "/repos/fenny/fiber/pulls/1000"},
+ {"GET", "/repos/fenny/fiber/pulls/1000/commits"},
+ {"GET", "/repos/fenny/fiber/pulls/1000/files"},
+ {"GET", "/repos/fenny/fiber/pulls/1000/merge"},
+ {"PUT", "/repos/fenny/fiber/pulls/1000/merge"},
+ {"GET", "/repos/fenny/fiber/pulls/1000/comments"},
+ {"GET", "/repos/fenny/fiber/pulls/comments"},
+ {"GET", "/repos/fenny/fiber/pulls/comments/1000"},
+ {"PUT", "/repos/fenny/fiber/pulls/1000/comments"},
+ {"PATCH", "/repos/fenny/fiber/pulls/comments/1000"},
+ {"DELETE", "/repos/fenny/fiber/pulls/comments/1000"},
-// // Users
-// {"GET", "/users/fenny"},
-// {"GET", "/user"},
-// {"PATCH", "/user"},
-// {"GET", "/users"},
-// {"GET", "/user/emails"},
-// {"POST", "/user/emails"},
-// {"DELETE", "/user/emails"},
-// {"GET", "/users/fenny/followers"},
-// {"GET", "/user/followers"},
-// {"GET", "/users/fenny/following"},
-// {"GET", "/user/following"},
-// {"GET", "/user/following/fenny"},
-// {"GET", "/users/fenny/following/renan"},
-// {"PUT", "/user/following/fenny"},
-// {"DELETE", "/user/following/fenny"},
-// {"GET", "/users/fenny/keys"},
-// {"GET", "/user/keys"},
-// {"GET", "/user/keys/1337"},
-// {"POST", "/user/keys"},
-// {"PATCH", "/user/keys/1337"},
-// {"DELETE", "/user/keys/1337"},
-// }
+ // Repositories
+ {"GET", "/user/repos"},
+ {"GET", "/users/fenny/repos"},
+ {"GET", "/orgs/gofiber/repos"},
+ {"GET", "/repositories"},
+ {"POST", "/user/repos"},
+ {"POST", "/orgs/gofiber/repos"},
+ {"GET", "/repos/fenny/fiber"},
+ {"PATCH", "/repos/fenny/fiber"},
+ {"GET", "/repos/fenny/fiber/contributors"},
+ {"GET", "/repos/fenny/fiber/languages"},
+ {"GET", "/repos/fenny/fiber/teams"},
+ {"GET", "/repos/fenny/fiber/tags"},
+ {"GET", "/repos/fenny/fiber/branches"},
+ {"GET", "/repos/fenny/fiber/branches/master"},
+ {"DELETE", "/repos/fenny/fiber"},
+ {"GET", "/repos/fenny/fiber/collaborators"},
+ {"GET", "/repos/fenny/fiber/collaborators/fenny"},
+ {"PUT", "/repos/fenny/fiber/collaborators/fenny"},
+ {"DELETE", "/repos/fenny/fiber/collaborators/fenny"},
+ {"GET", "/repos/fenny/fiber/comments"},
+ {"GET", "/repos/fenny/fiber/commits/v948b24g98ubngw9082bn02giub/comments"},
+ {"POST", "/repos/fenny/fiber/commits/v948b24g98ubngw9082bn02giub/comments"},
+ {"GET", "/repos/fenny/fiber/comments/1337"},
+ {"PATCH", "/repos/fenny/fiber/comments/1337"},
+ {"DELETE", "/repos/fenny/fiber/comments/1337"},
+ {"GET", "/repos/fenny/fiber/commits"},
+ {"GET", "/repos/fenny/fiber/commits/v948b24g98ubngw9082bn02giub"},
+ {"GET", "/repos/fenny/fiber/readme"},
+ {"GET", "/repos/fenny/fiber/contents/im/a/wildcard"},
+ {"PUT", "/repos/fenny/fiber/contents/im/a/wildcard"},
+ {"DELETE", "/repos/fenny/fiber/contents/im/a/wildcard"},
+ {"GET", "/repos/fenny/fiber/gzip/google"},
+ {"GET", "/repos/fenny/fiber/keys"},
+ {"GET", "/repos/fenny/fiber/keys/1337"},
+ {"POST", "/repos/fenny/fiber/keys"},
+ {"PATCH", "/repos/fenny/fiber/keys/1337"},
+ {"DELETE", "/repos/fenny/fiber/keys/1337"},
+ {"GET", "/repos/fenny/fiber/downloads"},
+ {"GET", "/repos/fenny/fiber/downloads/1337"},
+ {"DELETE", "/repos/fenny/fiber/downloads/1337"},
+ {"GET", "/repos/fenny/fiber/forks"},
+ {"POST", "/repos/fenny/fiber/forks"},
+ {"GET", "/repos/fenny/fiber/hooks"},
+ {"GET", "/repos/fenny/fiber/hooks/1337"},
+ {"POST", "/repos/fenny/fiber/hooks"},
+ {"PATCH", "/repos/fenny/fiber/hooks/1337"},
+ {"POST", "/repos/fenny/fiber/hooks/1337/tests"},
+ {"DELETE", "/repos/fenny/fiber/hooks/1337"},
+ {"POST", "/repos/fenny/fiber/merges"},
+ {"GET", "/repos/fenny/fiber/releases"},
+ {"GET", "/repos/fenny/fiber/releases/1337"},
+ {"POST", "/repos/fenny/fiber/releases"},
+ {"PATCH", "/repos/fenny/fiber/releases/1337"},
+ {"DELETE", "/repos/fenny/fiber/releases/1337"},
+ {"GET", "/repos/fenny/fiber/releases/1337/assets"},
+ {"GET", "/repos/fenny/fiber/stats/contributors"},
+ {"GET", "/repos/fenny/fiber/stats/commit_activity"},
+ {"GET", "/repos/fenny/fiber/stats/code_frequency"},
+ {"GET", "/repos/fenny/fiber/stats/participation"},
+ {"GET", "/repos/fenny/fiber/stats/punch_card"},
+ {"GET", "/repos/fenny/fiber/statuses/google"},
+ {"POST", "/repos/fenny/fiber/statuses/google"},
-// var githubAPI = []testRoute{
-// // OAuth Authorizations
-// {"GET", "/authorizations"},
-// {"GET", "/authorizations/:id"},
-// {"POST", "/authorizations"},
-// {"PUT", "/authorizations/clients/:client_id"},
-// {"PATCH", "/authorizations/:id"},
-// {"DELETE", "/authorizations/:id"},
-// {"GET", "/applications/:client_id/tokens/:access_token"},
-// {"DELETE", "/applications/:client_id/tokens"},
-// {"DELETE", "/applications/:client_id/tokens/:access_token"},
+ // Search
+ {"GET", "/search/repositories"},
+ {"GET", "/search/code"},
+ {"GET", "/search/issues"},
+ {"GET", "/search/users"},
+ {"GET", "/legacy/issues/search/fenny/fibersitory/locked/finish"},
+ {"GET", "/legacy/repos/search/finish"},
+ {"GET", "/legacy/user/search/finish"},
+ {"GET", "/legacy/user/email/info@gofiber.io"},
-// // Activity
-// {"GET", "/events"},
-// {"GET", "/repos/:owner/:repo/events"},
-// {"GET", "/networks/:owner/:repo/events"},
-// {"GET", "/orgs/:org/events"},
-// {"GET", "/users/:user/received_events"},
-// {"GET", "/users/:user/received_events/public"},
-// {"GET", "/users/:user/events"},
-// {"GET", "/users/:user/events/public"},
-// {"GET", "/users/:user/events/orgs/:org"},
-// {"GET", "/feeds"},
-// {"GET", "/notifications"},
-// {"GET", "/repos/:owner/:repo/notifications"},
-// {"PUT", "/notifications"},
-// {"PUT", "/repos/:owner/:repo/notifications"},
-// {"GET", "/notifications/threads/:id"},
-// {"PATCH", "/notifications/threads/:id"},
-// {"GET", "/notifications/threads/:id/subscription"},
-// {"PUT", "/notifications/threads/:id/subscription"},
-// {"DELETE", "/notifications/threads/:id/subscription"},
-// {"GET", "/repos/:owner/:repo/stargazers"},
-// {"GET", "/users/:user/starred"},
-// {"GET", "/user/starred"},
-// {"GET", "/user/starred/:owner/:repo"},
-// {"PUT", "/user/starred/:owner/:repo"},
-// {"DELETE", "/user/starred/:owner/:repo"},
-// {"GET", "/repos/:owner/:repo/subscribers"},
-// {"GET", "/users/:user/subscriptions"},
-// {"GET", "/user/subscriptions"},
-// {"GET", "/repos/:owner/:repo/subscription"},
-// {"PUT", "/repos/:owner/:repo/subscription"},
-// {"DELETE", "/repos/:owner/:repo/subscription"},
-// {"GET", "/user/subscriptions/:owner/:repo"},
-// {"PUT", "/user/subscriptions/:owner/:repo"},
-// {"DELETE", "/user/subscriptions/:owner/:repo"},
+ // Users
+ {"GET", "/users/fenny"},
+ {"GET", "/user"},
+ {"PATCH", "/user"},
+ {"GET", "/users"},
+ {"GET", "/user/emails"},
+ {"POST", "/user/emails"},
+ {"DELETE", "/user/emails"},
+ {"GET", "/users/fenny/followers"},
+ {"GET", "/user/followers"},
+ {"GET", "/users/fenny/following"},
+ {"GET", "/user/following"},
+ {"GET", "/user/following/fenny"},
+ {"GET", "/users/fenny/following/renan"},
+ {"PUT", "/user/following/fenny"},
+ {"DELETE", "/user/following/fenny"},
+ {"GET", "/users/fenny/keys"},
+ {"GET", "/user/keys"},
+ {"GET", "/user/keys/1337"},
+ {"POST", "/user/keys"},
+ {"PATCH", "/user/keys/1337"},
+ {"DELETE", "/user/keys/1337"},
+}
-// // Gists
-// {"GET", "/users/:user/gists"},
-// {"GET", "/gists"},
-// {"GET", "/gists/public"},
-// {"GET", "/gists/starred"},
-// {"GET", "/gists/:id"},
-// {"POST", "/gists"},
-// {"PATCH", "/gists/:id"},
-// {"PUT", "/gists/:id/star"},
-// {"DELETE", "/gists/:id/star"},
-// {"GET", "/gists/:id/star"},
-// {"POST", "/gists/:id/forks"},
-// {"DELETE", "/gists/:id"},
+var githubAPI = []testRoute{
+ // OAuth Authorizations
+ {"GET", "/authorizations"},
+ {"GET", "/authorizations/:id"},
+ {"POST", "/authorizations"},
+ {"PUT", "/authorizations/clients/:client_id"},
+ {"PATCH", "/authorizations/:id"},
+ {"DELETE", "/authorizations/:id"},
+ {"GET", "/applications/:client_id/tokens/:access_token"},
+ {"DELETE", "/applications/:client_id/tokens"},
+ {"DELETE", "/applications/:client_id/tokens/:access_token"},
-// // Git Data
-// {"GET", "/repos/:owner/:repo/git/blobs/:sha"},
-// {"POST", "/repos/:owner/:repo/git/blobs"},
-// {"GET", "/repos/:owner/:repo/git/commits/:sha"},
-// {"POST", "/repos/:owner/:repo/git/commits"},
-// {"GET", "/repos/:owner/:repo/git/refs/*"},
-// {"GET", "/repos/:owner/:repo/git/refs"},
-// {"POST", "/repos/:owner/:repo/git/refs"},
-// {"PATCH", "/repos/:owner/:repo/git/refs/*"},
-// {"DELETE", "/repos/:owner/:repo/git/refs/*"},
-// {"GET", "/repos/:owner/:repo/git/tags/:sha"},
-// {"POST", "/repos/:owner/:repo/git/tags"},
-// {"GET", "/repos/:owner/:repo/git/trees/:sha"},
-// {"POST", "/repos/:owner/:repo/git/trees"},
+ // Activity
+ {"GET", "/events"},
+ {"GET", "/repos/:owner/:repo/events"},
+ {"GET", "/networks/:owner/:repo/events"},
+ {"GET", "/orgs/:org/events"},
+ {"GET", "/users/:user/received_events"},
+ {"GET", "/users/:user/received_events/public"},
+ {"GET", "/users/:user/events"},
+ {"GET", "/users/:user/events/public"},
+ {"GET", "/users/:user/events/orgs/:org"},
+ {"GET", "/feeds"},
+ {"GET", "/notifications"},
+ {"GET", "/repos/:owner/:repo/notifications"},
+ {"PUT", "/notifications"},
+ {"PUT", "/repos/:owner/:repo/notifications"},
+ {"GET", "/notifications/threads/:id"},
+ {"PATCH", "/notifications/threads/:id"},
+ {"GET", "/notifications/threads/:id/subscription"},
+ {"PUT", "/notifications/threads/:id/subscription"},
+ {"DELETE", "/notifications/threads/:id/subscription"},
+ {"GET", "/repos/:owner/:repo/stargazers"},
+ {"GET", "/users/:user/starred"},
+ {"GET", "/user/starred"},
+ {"GET", "/user/starred/:owner/:repo"},
+ {"PUT", "/user/starred/:owner/:repo"},
+ {"DELETE", "/user/starred/:owner/:repo"},
+ {"GET", "/repos/:owner/:repo/subscribers"},
+ {"GET", "/users/:user/subscriptions"},
+ {"GET", "/user/subscriptions"},
+ {"GET", "/repos/:owner/:repo/subscription"},
+ {"PUT", "/repos/:owner/:repo/subscription"},
+ {"DELETE", "/repos/:owner/:repo/subscription"},
+ {"GET", "/user/subscriptions/:owner/:repo"},
+ {"PUT", "/user/subscriptions/:owner/:repo"},
+ {"DELETE", "/user/subscriptions/:owner/:repo"},
-// // Issues
-// {"GET", "/issues"},
-// {"GET", "/user/issues"},
-// {"GET", "/orgs/:org/issues"},
-// {"GET", "/repos/:owner/:repo/issues"},
-// {"GET", "/repos/:owner/:repo/issues/:number"},
-// {"POST", "/repos/:owner/:repo/issues"},
-// {"PATCH", "/repos/:owner/:repo/issues/:number"},
-// {"GET", "/repos/:owner/:repo/assignees"},
-// {"GET", "/repos/:owner/:repo/assignees/:assignee"},
-// {"GET", "/repos/:owner/:repo/issues/:number/comments"},
-// {"GET", "/repos/:owner/:repo/issues/comments"},
-// {"GET", "/repos/:owner/:repo/issues/comments/:id"},
-// {"POST", "/repos/:owner/:repo/issues/:number/comments"},
-// {"PATCH", "/repos/:owner/:repo/issues/comments/:id"},
-// {"DELETE", "/repos/:owner/:repo/issues/comments/:id"},
-// {"GET", "/repos/:owner/:repo/issues/:number/events"},
-// {"GET", "/repos/:owner/:repo/issues/events"},
-// {"GET", "/repos/:owner/:repo/issues/events/:id"},
-// {"GET", "/repos/:owner/:repo/labels"},
-// {"GET", "/repos/:owner/:repo/labels/:name"},
-// {"POST", "/repos/:owner/:repo/labels"},
-// {"PATCH", "/repos/:owner/:repo/labels/:name"},
-// {"DELETE", "/repos/:owner/:repo/labels/:name"},
-// {"GET", "/repos/:owner/:repo/issues/:number/labels"},
-// {"POST", "/repos/:owner/:repo/issues/:number/labels"},
-// {"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name"},
-// {"PUT", "/repos/:owner/:repo/issues/:number/labels"},
-// {"DELETE", "/repos/:owner/:repo/issues/:number/labels"},
-// {"GET", "/repos/:owner/:repo/milestones/:number/labels"},
-// {"GET", "/repos/:owner/:repo/milestones"},
-// {"GET", "/repos/:owner/:repo/milestones/:number"},
-// {"POST", "/repos/:owner/:repo/milestones"},
-// {"PATCH", "/repos/:owner/:repo/milestones/:number"},
-// {"DELETE", "/repos/:owner/:repo/milestones/:number"},
+ // Gists
+ {"GET", "/users/:user/gists"},
+ {"GET", "/gists"},
+ {"GET", "/gists/public"},
+ {"GET", "/gists/starred"},
+ {"GET", "/gists/:id"},
+ {"POST", "/gists"},
+ {"PATCH", "/gists/:id"},
+ {"PUT", "/gists/:id/star"},
+ {"DELETE", "/gists/:id/star"},
+ {"GET", "/gists/:id/star"},
+ {"POST", "/gists/:id/forks"},
+ {"DELETE", "/gists/:id"},
-// // Miscellaneous
-// {"GET", "/emojis"},
-// {"GET", "/gitignore/templates"},
-// {"GET", "/gitignore/templates/:name"},
-// {"POST", "/markdown"},
-// {"POST", "/markdown/raw"},
-// {"GET", "/meta"},
-// {"GET", "/rate_limit"},
+ // Git Data
+ {"GET", "/repos/:owner/:repo/git/blobs/:sha"},
+ {"POST", "/repos/:owner/:repo/git/blobs"},
+ {"GET", "/repos/:owner/:repo/git/commits/:sha"},
+ {"POST", "/repos/:owner/:repo/git/commits"},
+ {"GET", "/repos/:owner/:repo/git/refs/*"},
+ {"GET", "/repos/:owner/:repo/git/refs"},
+ {"POST", "/repos/:owner/:repo/git/refs"},
+ {"PATCH", "/repos/:owner/:repo/git/refs/*"},
+ {"DELETE", "/repos/:owner/:repo/git/refs/*"},
+ {"GET", "/repos/:owner/:repo/git/tags/:sha"},
+ {"POST", "/repos/:owner/:repo/git/tags"},
+ {"GET", "/repos/:owner/:repo/git/trees/:sha"},
+ {"POST", "/repos/:owner/:repo/git/trees"},
-// // Organizations
-// {"GET", "/users/:user/orgs"},
-// {"GET", "/user/orgs"},
-// {"GET", "/orgs/:org"},
-// {"PATCH", "/orgs/:org"},
-// {"GET", "/orgs/:org/members"},
-// {"GET", "/orgs/:org/members/:user"},
-// {"DELETE", "/orgs/:org/members/:user"},
-// {"GET", "/orgs/:org/public_members"},
-// {"GET", "/orgs/:org/public_members/:user"},
-// {"PUT", "/orgs/:org/public_members/:user"},
-// {"DELETE", "/orgs/:org/public_members/:user"},
-// {"GET", "/orgs/:org/teams"},
-// {"GET", "/teams/:id"},
-// {"POST", "/orgs/:org/teams"},
-// {"PATCH", "/teams/:id"},
-// {"DELETE", "/teams/:id"},
-// {"GET", "/teams/:id/members"},
-// {"GET", "/teams/:id/members/:user"},
-// {"PUT", "/teams/:id/members/:user"},
-// {"DELETE", "/teams/:id/members/:user"},
-// {"GET", "/teams/:id/repos"},
-// {"GET", "/teams/:id/repos/:owner/:repo"},
-// {"PUT", "/teams/:id/repos/:owner/:repo"},
-// {"DELETE", "/teams/:id/repos/:owner/:repo"},
-// {"GET", "/user/teams"},
+ // Issues
+ {"GET", "/issues"},
+ {"GET", "/user/issues"},
+ {"GET", "/orgs/:org/issues"},
+ {"GET", "/repos/:owner/:repo/issues"},
+ {"GET", "/repos/:owner/:repo/issues/:number"},
+ {"POST", "/repos/:owner/:repo/issues"},
+ {"PATCH", "/repos/:owner/:repo/issues/:number"},
+ {"GET", "/repos/:owner/:repo/assignees"},
+ {"GET", "/repos/:owner/:repo/assignees/:assignee"},
+ {"GET", "/repos/:owner/:repo/issues/:number/comments"},
+ {"GET", "/repos/:owner/:repo/issues/comments"},
+ {"GET", "/repos/:owner/:repo/issues/comments/:id"},
+ {"POST", "/repos/:owner/:repo/issues/:number/comments"},
+ {"PATCH", "/repos/:owner/:repo/issues/comments/:id"},
+ {"DELETE", "/repos/:owner/:repo/issues/comments/:id"},
+ {"GET", "/repos/:owner/:repo/issues/:number/events"},
+ {"GET", "/repos/:owner/:repo/issues/events"},
+ {"GET", "/repos/:owner/:repo/issues/events/:id"},
+ {"GET", "/repos/:owner/:repo/labels"},
+ {"GET", "/repos/:owner/:repo/labels/:name"},
+ {"POST", "/repos/:owner/:repo/labels"},
+ {"PATCH", "/repos/:owner/:repo/labels/:name"},
+ {"DELETE", "/repos/:owner/:repo/labels/:name"},
+ {"GET", "/repos/:owner/:repo/issues/:number/labels"},
+ {"POST", "/repos/:owner/:repo/issues/:number/labels"},
+ {"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name"},
+ {"PUT", "/repos/:owner/:repo/issues/:number/labels"},
+ {"DELETE", "/repos/:owner/:repo/issues/:number/labels"},
+ {"GET", "/repos/:owner/:repo/milestones/:number/labels"},
+ {"GET", "/repos/:owner/:repo/milestones"},
+ {"GET", "/repos/:owner/:repo/milestones/:number"},
+ {"POST", "/repos/:owner/:repo/milestones"},
+ {"PATCH", "/repos/:owner/:repo/milestones/:number"},
+ {"DELETE", "/repos/:owner/:repo/milestones/:number"},
-// // Pull Requests
-// {"GET", "/repos/:owner/:repo/pulls"},
-// {"GET", "/repos/:owner/:repo/pulls/:number"},
-// {"POST", "/repos/:owner/:repo/pulls"},
-// {"PATCH", "/repos/:owner/:repo/pulls/:number"},
-// {"GET", "/repos/:owner/:repo/pulls/:number/commits"},
-// {"GET", "/repos/:owner/:repo/pulls/:number/files"},
-// {"GET", "/repos/:owner/:repo/pulls/:number/merge"},
-// {"PUT", "/repos/:owner/:repo/pulls/:number/merge"},
-// {"GET", "/repos/:owner/:repo/pulls/:number/comments"},
-// {"GET", "/repos/:owner/:repo/pulls/comments"},
-// {"GET", "/repos/:owner/:repo/pulls/comments/:number"},
-// {"PUT", "/repos/:owner/:repo/pulls/:number/comments"},
-// {"PATCH", "/repos/:owner/:repo/pulls/comments/:number"},
-// {"DELETE", "/repos/:owner/:repo/pulls/comments/:number"},
+ // Miscellaneous
+ {"GET", "/emojis"},
+ {"GET", "/gitignore/templates"},
+ {"GET", "/gitignore/templates/:name"},
+ {"POST", "/markdown"},
+ {"POST", "/markdown/raw"},
+ {"GET", "/meta"},
+ {"GET", "/rate_limit"},
-// // Repositories
-// {"GET", "/user/repos"},
-// {"GET", "/users/:user/repos"},
-// {"GET", "/orgs/:org/repos"},
-// {"GET", "/repositories"},
-// {"POST", "/user/repos"},
-// {"POST", "/orgs/:org/repos"},
-// {"GET", "/repos/:owner/:repo"},
-// {"PATCH", "/repos/:owner/:repo"},
-// {"GET", "/repos/:owner/:repo/contributors"},
-// {"GET", "/repos/:owner/:repo/languages"},
-// {"GET", "/repos/:owner/:repo/teams"},
-// {"GET", "/repos/:owner/:repo/tags"},
-// {"GET", "/repos/:owner/:repo/branches"},
-// {"GET", "/repos/:owner/:repo/branches/:branch"},
-// {"DELETE", "/repos/:owner/:repo"},
-// {"GET", "/repos/:owner/:repo/collaborators"},
-// {"GET", "/repos/:owner/:repo/collaborators/:user"},
-// {"PUT", "/repos/:owner/:repo/collaborators/:user"},
-// {"DELETE", "/repos/:owner/:repo/collaborators/:user"},
-// {"GET", "/repos/:owner/:repo/comments"},
-// {"GET", "/repos/:owner/:repo/commits/:sha/comments"},
-// {"POST", "/repos/:owner/:repo/commits/:sha/comments"},
-// {"GET", "/repos/:owner/:repo/comments/:id"},
-// {"PATCH", "/repos/:owner/:repo/comments/:id"},
-// {"DELETE", "/repos/:owner/:repo/comments/:id"},
-// {"GET", "/repos/:owner/:repo/commits"},
-// {"GET", "/repos/:owner/:repo/commits/:sha"},
-// {"GET", "/repos/:owner/:repo/readme"},
-// {"GET", "/repos/:owner/:repo/contents/*"},
-// {"PUT", "/repos/:owner/:repo/contents/*"},
-// {"DELETE", "/repos/:owner/:repo/contents/*"},
-// {"GET", "/repos/:owner/:repo/:archive_format/:ref"},
-// {"GET", "/repos/:owner/:repo/keys"},
-// {"GET", "/repos/:owner/:repo/keys/:id"},
-// {"POST", "/repos/:owner/:repo/keys"},
-// {"PATCH", "/repos/:owner/:repo/keys/:id"},
-// {"DELETE", "/repos/:owner/:repo/keys/:id"},
-// {"GET", "/repos/:owner/:repo/downloads"},
-// {"GET", "/repos/:owner/:repo/downloads/:id"},
-// {"DELETE", "/repos/:owner/:repo/downloads/:id"},
-// {"GET", "/repos/:owner/:repo/forks"},
-// {"POST", "/repos/:owner/:repo/forks"},
-// {"GET", "/repos/:owner/:repo/hooks"},
-// {"GET", "/repos/:owner/:repo/hooks/:id"},
-// {"POST", "/repos/:owner/:repo/hooks"},
-// {"PATCH", "/repos/:owner/:repo/hooks/:id"},
-// {"POST", "/repos/:owner/:repo/hooks/:id/tests"},
-// {"DELETE", "/repos/:owner/:repo/hooks/:id"},
-// {"POST", "/repos/:owner/:repo/merges"},
-// {"GET", "/repos/:owner/:repo/releases"},
-// {"GET", "/repos/:owner/:repo/releases/:id"},
-// {"POST", "/repos/:owner/:repo/releases"},
-// {"PATCH", "/repos/:owner/:repo/releases/:id"},
-// {"DELETE", "/repos/:owner/:repo/releases/:id"},
-// {"GET", "/repos/:owner/:repo/releases/:id/assets"},
-// {"GET", "/repos/:owner/:repo/stats/contributors"},
-// {"GET", "/repos/:owner/:repo/stats/commit_activity"},
-// {"GET", "/repos/:owner/:repo/stats/code_frequency"},
-// {"GET", "/repos/:owner/:repo/stats/participation"},
-// {"GET", "/repos/:owner/:repo/stats/punch_card"},
-// {"GET", "/repos/:owner/:repo/statuses/:ref"},
-// {"POST", "/repos/:owner/:repo/statuses/:ref"},
+ // Organizations
+ {"GET", "/users/:user/orgs"},
+ {"GET", "/user/orgs"},
+ {"GET", "/orgs/:org"},
+ {"PATCH", "/orgs/:org"},
+ {"GET", "/orgs/:org/members"},
+ {"GET", "/orgs/:org/members/:user"},
+ {"DELETE", "/orgs/:org/members/:user"},
+ {"GET", "/orgs/:org/public_members"},
+ {"GET", "/orgs/:org/public_members/:user"},
+ {"PUT", "/orgs/:org/public_members/:user"},
+ {"DELETE", "/orgs/:org/public_members/:user"},
+ {"GET", "/orgs/:org/teams"},
+ {"GET", "/teams/:id"},
+ {"POST", "/orgs/:org/teams"},
+ {"PATCH", "/teams/:id"},
+ {"DELETE", "/teams/:id"},
+ {"GET", "/teams/:id/members"},
+ {"GET", "/teams/:id/members/:user"},
+ {"PUT", "/teams/:id/members/:user"},
+ {"DELETE", "/teams/:id/members/:user"},
+ {"GET", "/teams/:id/repos"},
+ {"GET", "/teams/:id/repos/:owner/:repo"},
+ {"PUT", "/teams/:id/repos/:owner/:repo"},
+ {"DELETE", "/teams/:id/repos/:owner/:repo"},
+ {"GET", "/user/teams"},
-// // Search
-// {"GET", "/search/repositories"},
-// {"GET", "/search/code"},
-// {"GET", "/search/issues"},
-// {"GET", "/search/users"},
-// {"GET", "/legacy/issues/search/:owner/:repository/:state/:keyword"},
-// {"GET", "/legacy/repos/search/:keyword"},
-// {"GET", "/legacy/user/search/:keyword"},
-// {"GET", "/legacy/user/email/:email"},
+ // Pull Requests
+ {"GET", "/repos/:owner/:repo/pulls"},
+ {"GET", "/repos/:owner/:repo/pulls/:number"},
+ {"POST", "/repos/:owner/:repo/pulls"},
+ {"PATCH", "/repos/:owner/:repo/pulls/:number"},
+ {"GET", "/repos/:owner/:repo/pulls/:number/commits"},
+ {"GET", "/repos/:owner/:repo/pulls/:number/files"},
+ {"GET", "/repos/:owner/:repo/pulls/:number/merge"},
+ {"PUT", "/repos/:owner/:repo/pulls/:number/merge"},
+ {"GET", "/repos/:owner/:repo/pulls/:number/comments"},
+ {"GET", "/repos/:owner/:repo/pulls/comments"},
+ {"GET", "/repos/:owner/:repo/pulls/comments/:number"},
+ {"PUT", "/repos/:owner/:repo/pulls/:number/comments"},
+ {"PATCH", "/repos/:owner/:repo/pulls/comments/:number"},
+ {"DELETE", "/repos/:owner/:repo/pulls/comments/:number"},
-// // Users
-// {"GET", "/users/:user"},
-// {"GET", "/user"},
-// {"PATCH", "/user"},
-// {"GET", "/users"},
-// {"GET", "/user/emails"},
-// {"POST", "/user/emails"},
-// {"DELETE", "/user/emails"},
-// {"GET", "/users/:user/followers"},
-// {"GET", "/user/followers"},
-// {"GET", "/users/:user/following"},
-// {"GET", "/user/following"},
-// {"GET", "/user/following/:user"},
-// {"GET", "/users/:user/following/:target_user"},
-// {"PUT", "/user/following/:user"},
-// {"DELETE", "/user/following/:user"},
-// {"GET", "/users/:user/keys"},
-// {"GET", "/user/keys"},
-// {"GET", "/user/keys/:id"},
-// {"POST", "/user/keys"},
-// {"PATCH", "/user/keys/:id"},
-// {"DELETE", "/user/keys/:id"},
-// }
+ // Repositories
+ {"GET", "/user/repos"},
+ {"GET", "/users/:user/repos"},
+ {"GET", "/orgs/:org/repos"},
+ {"GET", "/repositories"},
+ {"POST", "/user/repos"},
+ {"POST", "/orgs/:org/repos"},
+ {"GET", "/repos/:owner/:repo"},
+ {"PATCH", "/repos/:owner/:repo"},
+ {"GET", "/repos/:owner/:repo/contributors"},
+ {"GET", "/repos/:owner/:repo/languages"},
+ {"GET", "/repos/:owner/:repo/teams"},
+ {"GET", "/repos/:owner/:repo/tags"},
+ {"GET", "/repos/:owner/:repo/branches"},
+ {"GET", "/repos/:owner/:repo/branches/:branch"},
+ {"DELETE", "/repos/:owner/:repo"},
+ {"GET", "/repos/:owner/:repo/collaborators"},
+ {"GET", "/repos/:owner/:repo/collaborators/:user"},
+ {"PUT", "/repos/:owner/:repo/collaborators/:user"},
+ {"DELETE", "/repos/:owner/:repo/collaborators/:user"},
+ {"GET", "/repos/:owner/:repo/comments"},
+ {"GET", "/repos/:owner/:repo/commits/:sha/comments"},
+ {"POST", "/repos/:owner/:repo/commits/:sha/comments"},
+ {"GET", "/repos/:owner/:repo/comments/:id"},
+ {"PATCH", "/repos/:owner/:repo/comments/:id"},
+ {"DELETE", "/repos/:owner/:repo/comments/:id"},
+ {"GET", "/repos/:owner/:repo/commits"},
+ {"GET", "/repos/:owner/:repo/commits/:sha"},
+ {"GET", "/repos/:owner/:repo/readme"},
+ {"GET", "/repos/:owner/:repo/contents/*"},
+ {"PUT", "/repos/:owner/:repo/contents/*"},
+ {"DELETE", "/repos/:owner/:repo/contents/*"},
+ {"GET", "/repos/:owner/:repo/:archive_format/:ref"},
+ {"GET", "/repos/:owner/:repo/keys"},
+ {"GET", "/repos/:owner/:repo/keys/:id"},
+ {"POST", "/repos/:owner/:repo/keys"},
+ {"PATCH", "/repos/:owner/:repo/keys/:id"},
+ {"DELETE", "/repos/:owner/:repo/keys/:id"},
+ {"GET", "/repos/:owner/:repo/downloads"},
+ {"GET", "/repos/:owner/:repo/downloads/:id"},
+ {"DELETE", "/repos/:owner/:repo/downloads/:id"},
+ {"GET", "/repos/:owner/:repo/forks"},
+ {"POST", "/repos/:owner/:repo/forks"},
+ {"GET", "/repos/:owner/:repo/hooks"},
+ {"GET", "/repos/:owner/:repo/hooks/:id"},
+ {"POST", "/repos/:owner/:repo/hooks"},
+ {"PATCH", "/repos/:owner/:repo/hooks/:id"},
+ {"POST", "/repos/:owner/:repo/hooks/:id/tests"},
+ {"DELETE", "/repos/:owner/:repo/hooks/:id"},
+ {"POST", "/repos/:owner/:repo/merges"},
+ {"GET", "/repos/:owner/:repo/releases"},
+ {"GET", "/repos/:owner/:repo/releases/:id"},
+ {"POST", "/repos/:owner/:repo/releases"},
+ {"PATCH", "/repos/:owner/:repo/releases/:id"},
+ {"DELETE", "/repos/:owner/:repo/releases/:id"},
+ {"GET", "/repos/:owner/:repo/releases/:id/assets"},
+ {"GET", "/repos/:owner/:repo/stats/contributors"},
+ {"GET", "/repos/:owner/:repo/stats/commit_activity"},
+ {"GET", "/repos/:owner/:repo/stats/code_frequency"},
+ {"GET", "/repos/:owner/:repo/stats/participation"},
+ {"GET", "/repos/:owner/:repo/stats/punch_card"},
+ {"GET", "/repos/:owner/:repo/statuses/:ref"},
+ {"POST", "/repos/:owner/:repo/statuses/:ref"},
+
+ // Search
+ {"GET", "/search/repositories"},
+ {"GET", "/search/code"},
+ {"GET", "/search/issues"},
+ {"GET", "/search/users"},
+ {"GET", "/legacy/issues/search/:owner/:repository/:state/:keyword"},
+ {"GET", "/legacy/repos/search/:keyword"},
+ {"GET", "/legacy/user/search/:keyword"},
+ {"GET", "/legacy/user/email/:email"},
+
+ // Users
+ {"GET", "/users/:user"},
+ {"GET", "/user"},
+ {"PATCH", "/user"},
+ {"GET", "/users"},
+ {"GET", "/user/emails"},
+ {"POST", "/user/emails"},
+ {"DELETE", "/user/emails"},
+ {"GET", "/users/:user/followers"},
+ {"GET", "/user/followers"},
+ {"GET", "/users/:user/following"},
+ {"GET", "/user/following"},
+ {"GET", "/user/following/:user"},
+ {"GET", "/users/:user/following/:target_user"},
+ {"PUT", "/user/following/:user"},
+ {"DELETE", "/user/following/:user"},
+ {"GET", "/users/:user/keys"},
+ {"GET", "/user/keys"},
+ {"GET", "/user/keys/:id"},
+ {"POST", "/user/keys"},
+ {"PATCH", "/user/keys/:id"},
+ {"DELETE", "/user/keys/:id"},
+}
diff --git a/router_test.go b/router_test.go
index f82b9d14..2147977c 100644
--- a/router_test.go
+++ b/router_test.go
@@ -6,240 +6,3 @@
// ๐ค ucarion/urlpath - renanbastos93/fastpath - renewerner87/fastpath
package fiber
-
-import (
- "fmt"
- "reflect"
- "testing"
-)
-
-type testcase struct {
- uri string
- params []string
- ok bool
-}
-
-func Test_With_Param_And_Wildcard(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/v1/:param/*"),
- []testcase{
- {uri: "/api/v1/entity", params: []string{"entity", ""}, ok: true},
- {uri: "/api/v1/entity/", params: []string{"entity", ""}, ok: true},
- {uri: "/api/v1/entity/1", params: []string{"entity", "1"}, ok: true},
- {uri: "/api/v", params: nil, ok: false},
- {uri: "/api/v2", params: nil, ok: false},
- {uri: "/api/v1/", params: nil, ok: false},
- },
- )
-}
-
-func Test_With_A_Param_Optional(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/v1/:param?"),
- []testcase{
- {uri: "/api/v1", params: []string{""}, ok: true},
- {uri: "/api/v1/", params: []string{""}, ok: true},
- {uri: "/api/v1/optional", params: []string{"optional"}, ok: true},
- {uri: "/api/v", params: nil, ok: false},
- {uri: "/api/v2", params: nil, ok: false},
- {uri: "/api/xyz", params: nil, ok: false},
- },
- )
-}
-
-func Test_With_With_Wildcard(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/v1/*"),
- []testcase{
- {uri: "/api/v1", params: []string{""}, ok: true},
- {uri: "/api/v1/", params: []string{""}, ok: true},
- {uri: "/api/v1/entity", params: []string{"entity"}, ok: true},
- {uri: "/api/v1/entity/1/2", params: []string{"entity/1/2"}, ok: true},
- {uri: "/api/v", params: nil, ok: false},
- {uri: "/api/v2", params: nil, ok: false},
- {uri: "/api/abc", params: nil, ok: false},
- },
- )
-}
-func Test_With_With_Param(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/v1/:param"),
- []testcase{
- {uri: "/api/v1/entity", params: []string{"entity"}, ok: true},
- {uri: "/api/v1/entity/8728382", params: nil, ok: false},
- {uri: "/api/v1", params: nil, ok: false},
- {uri: "/api/v1/", params: nil, ok: false},
- },
- )
-}
-
-func Test_With_Without_A_Param_Or_Wildcard(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/v1/const"),
- []testcase{
- {uri: "/api/v1/const", params: []string{}, ok: true},
- {uri: "/api/v1", params: nil, ok: false},
- {uri: "/api/v1/", params: nil, ok: false},
- {uri: "/api/v1/something", params: nil, ok: false},
- },
- )
-}
-func Test_With_With_A_Param_And_Wildcard_Differents_Positions(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/v1/:param/abc/*"),
- []testcase{
- {uri: "/api/v1/well/abc/wildcard", params: []string{"well", "wildcard"}, ok: true},
- {uri: "/api/v1/well/abc/", params: []string{"well", ""}, ok: true},
- {uri: "/api/v1/well/abc", params: []string{"well", ""}, ok: true},
- {uri: "/api/v1/well/ttt", params: nil, ok: false},
- },
- )
-}
-func Test_With_With_Params_And_Optional(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/:day/:month?/:year?"),
- []testcase{
- {uri: "/api/1", params: []string{"1", "", ""}, ok: true},
- {uri: "/api/1/", params: []string{"1", "", ""}, ok: true},
- {uri: "/api/1/2", params: []string{"1", "2", ""}, ok: true},
- {uri: "/api/1/2/3", params: []string{"1", "2", "3"}, ok: true},
- {uri: "/api/", params: nil, ok: false},
- },
- )
-}
-func Test_With_With_Simple_Wildcard(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/*"),
- []testcase{
- {uri: "/api/", params: []string{""}, ok: true},
- {uri: "/api/joker", params: []string{"joker"}, ok: true},
- {uri: "/api", params: []string{""}, ok: true},
- {uri: "/api/v1/entity", params: []string{"v1/entity"}, ok: true},
- {uri: "/api2/v1/entity", params: nil, ok: false},
- {uri: "/api_ignore/v1/entity", params: nil, ok: false},
- },
- )
-}
-func Test_With_With_Wildcard_And_Optional(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/*/:param?"),
- []testcase{
- {uri: "/api/", params: []string{"", ""}, ok: true},
- {uri: "/api/joker", params: []string{"joker", ""}, ok: true},
- {uri: "/api/joker/batman", params: []string{"joker", "batman"}, ok: true},
- {uri: "/api/joker/batman/robin", params: []string{"joker/batman", "robin"}, ok: true},
- {uri: "/api/joker/batman/robin/1", params: []string{"joker/batman/robin", "1"}, ok: true},
- {uri: "/api", params: []string{"", ""}, ok: true},
- },
- )
-}
-func Test_With_With_Wildcard_And_Param(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/*/:param"),
- []testcase{
- {uri: "/api/test/abc", params: []string{"test", "abc"}, ok: true},
- {uri: "/api/joker/batman", params: []string{"joker", "batman"}, ok: true},
- {uri: "/api/joker/batman/robin", params: []string{"joker/batman", "robin"}, ok: true},
- {uri: "/api/joker/batman/robin/1", params: []string{"joker/batman/robin", "1"}, ok: true},
- {uri: "/api", params: nil, ok: false},
- },
- )
-}
-func Test_With_With_Wildcard_And_2Params(t *testing.T) {
- checkCases(
- t,
- parseParams("/api/*/:param/:param2"),
- []testcase{
- {uri: "/api/test/abc", params: nil, ok: false},
- {uri: "/api/joker/batman", params: nil, ok: false},
- {uri: "/api/joker/batman/robin", params: []string{"joker", "batman", "robin"}, ok: true},
- {uri: "/api/joker/batman/robin/1", params: []string{"joker/batman", "robin", "1"}, ok: true},
- {uri: "/api/joker/batman/robin/1/2", params: []string{"joker/batman/robin", "1", "2"}, ok: true},
- {uri: "/api", params: nil, ok: false},
- },
- )
-}
-func Test_With_With_Simple_Path(t *testing.T) {
- checkCases(
- t,
- parseParams("/"),
- []testcase{
- {uri: "/api", params: nil, ok: false},
- {uri: "", params: []string{}, ok: true},
- {uri: "/", params: []string{}, ok: true},
- },
- )
-}
-func Test_With_With_Empty_Path(t *testing.T) {
- checkCases(
- t,
- parseParams(""),
- []testcase{
- {uri: "/api", params: nil, ok: false},
- {uri: "", params: []string{}, ok: true},
- {uri: "/", params: []string{}, ok: true},
- },
- )
-}
-
-func Test_With_With_FileName(t *testing.T) {
- checkCases(
- t,
- parseParams("/config/abc.json"),
- []testcase{
- {uri: "/config/abc.json", params: []string{}, ok: true},
- {uri: "config/abc.json", params: nil, ok: false},
- {uri: "/config/efg.json", params: nil, ok: false},
- {uri: "/config", params: nil, ok: false},
- },
- )
-}
-
-func Test_With_With_FileName_And_Wildcard(t *testing.T) {
- checkCases(
- t,
- parseParams("/config/*.json"),
- []testcase{
- {uri: "/config/abc.json", params: []string{"abc.json"}, ok: true},
- {uri: "/config/efg.json", params: []string{"efg.json"}, ok: true},
- //{uri: "/config/efg.csv", params: nil, ok: false},// doesn`t work, current: params: "efg.csv", true
- {uri: "config/abc.json", params: nil, ok: false},
- {uri: "/config", params: nil, ok: false},
- },
- )
-}
-
-func Test_With_With_Simple_Path_And_NoMatch(t *testing.T) {
- checkCases(
- t,
- parseParams("/xyz"),
- []testcase{
- {uri: "xyz", params: nil, ok: false},
- {uri: "xyz/", params: nil, ok: false},
- },
- )
-}
-
-func checkCases(tParent *testing.T, parser parsedParams, tcases []testcase) {
- for _, tcase := range tcases {
- tParent.Run(fmt.Sprintf("%+v", tcase), func(t *testing.T) {
- params, ok := parser.matchParams(tcase.uri)
- if !reflect.DeepEqual(params, tcase.params) {
- t.Errorf("Path.Match() got = %v, want %v", params, tcase.params)
- }
- if ok != tcase.ok {
- t.Errorf("Path.Match() got1 = %v, want %v", ok, tcase.ok)
- }
- })
- }
-}
diff --git a/utils.go b/utils.go
index 2e1e8ba9..4a33b776 100644
--- a/utils.go
+++ b/utils.go
@@ -110,6 +110,30 @@ func getArgument(arg string) bool {
return false
}
+// return valid offer for header negotiation
+func getOffer(header string, offers ...string) string {
+ if len(offers) == 0 {
+ return ""
+ }
+ if header == "" {
+ return offers[0]
+ }
+
+ specs := strings.Split(header, ",")
+ for i := range offers {
+ for k := range specs {
+ spec := strings.TrimSpace(specs[k])
+ if strings.HasPrefix(spec, "*") {
+ return offers[i]
+ }
+ if strings.HasPrefix(spec, offers[i]) {
+ return offers[i]
+ }
+ }
+ }
+ return ""
+}
+
// Adapted from:
// https://github.com/jshttp/fresh/blob/10e0471669dbbfbfd8de65bc6efac2ddd0bfa057/index.js#L110
func parseTokenList(noneMatchBytes []byte) []string {
@@ -688,3 +712,163 @@ const (
StatusNotExtended = 510 // RFC 2774, 7
StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)
+
+// โ ๏ธ This path parser was based on urlpath by @ucarion (MIT License).
+// ๐ Modified for the Fiber router by @renanbastos93 & @renewerner87
+// ๐ค ucarion/urlpath - renanbastos93/fastpath - renewerner87/fastpath
+
+// paramsParser holds the path segments and param names
+type parsedParams struct {
+ segs []paramSeg
+ params []string
+}
+
+// paramsSeg holds the segment metadata
+type paramSeg struct {
+ Param string
+ Const string
+ IsParam bool
+ IsOptional bool
+ IsLast bool
+}
+
+var paramsDummy = make([]string, 100, 100)
+
+const wildcardParam string = "*"
+
+// New ...
+func getParams(pattern string) (p parsedParams) {
+ var patternCount int
+ aPattern := []string{""}
+ if pattern != "" {
+ aPattern = strings.Split(pattern, "/")[1:] // every route starts with an "/"
+ }
+ patternCount = len(aPattern)
+
+ var out = make([]paramSeg, patternCount)
+ var params []string
+ var segIndex int
+ for i := 0; i < patternCount; i++ {
+ partLen := len(aPattern[i])
+ if partLen == 0 { // skip empty parts
+ continue
+ }
+ // is parameter ?
+ if aPattern[i][0] == '*' || aPattern[i][0] == ':' {
+ out[segIndex] = paramSeg{
+ Param: getTrimmedParam(aPattern[i]),
+ IsParam: true,
+ IsOptional: aPattern[i] == wildcardParam || aPattern[i][partLen-1] == '?',
+ }
+ params = append(params, out[segIndex].Param)
+ } else {
+ // combine const segments
+ if segIndex > 0 && out[segIndex-1].IsParam == false {
+ segIndex--
+ out[segIndex].Const += "/" + aPattern[i]
+ // create new const segment
+ } else {
+ out[segIndex] = paramSeg{
+ Const: aPattern[i],
+ }
+ }
+ }
+ segIndex++
+ }
+ if segIndex == 0 {
+ segIndex++
+ }
+ out[segIndex-1].IsLast = true
+
+ p = parsedParams{segs: out[:segIndex:segIndex], params: params}
+ //fmt.Printf("%+v\n", p)
+ return
+}
+
+// Match ...
+func (p *parsedParams) getMatch(s string, partialCheck bool) ([]string, bool) {
+ lenKeys := len(p.params)
+ params := paramsDummy[0:lenKeys:lenKeys]
+ var i, j, paramsIterator, partLen int
+ if len(s) > 0 {
+ s = s[1:]
+ }
+ for index, segment := range p.segs {
+ partLen = len(s)
+ // check parameter
+ if segment.IsParam {
+ // determine parameter length
+ if segment.Param == wildcardParam {
+ if segment.IsLast {
+ i = partLen
+ } else {
+ // for the expressjs behavior -> "/api/*/:param" - "/api/joker/batman/robin/1" -> "joker/batman/robin", "1"
+ i = getCharPos(s, '/', strings.Count(s, "/")-(len(p.segs)-(index+1))+1)
+ }
+ } else {
+ i = strings.IndexByte(s, '/')
+ }
+ if i == -1 {
+ i = partLen
+ }
+
+ if false == segment.IsOptional && i == 0 {
+ return nil, false
+ }
+
+ params[paramsIterator] = s[:i]
+ paramsIterator++
+ } else {
+ // check const segment
+ i = len(segment.Const)
+ if partLen < i || (i == 0 && partLen > 0) || s[:i] != segment.Const || (partLen > i && s[i] != '/') {
+ return nil, false
+ }
+ }
+
+ // reduce founded part from the string
+ if partLen > 0 {
+ j = i + 1
+ if segment.IsLast || partLen < j {
+ j = i
+ }
+
+ s = s[j:]
+ }
+ }
+ if len(s) != 0 && !partialCheck {
+ return nil, false
+ }
+
+ return params, true
+}
+func getTrimmedParam(param string) string {
+ start := 0
+ end := len(param)
+
+ if param[start] != ':' { // is not a param
+ return param
+ }
+ start++
+ if param[end-1] == '?' { // is ?
+ end--
+ }
+
+ return param[start:end]
+}
+func getCharPos(s string, char byte, matchCount int) int {
+ if matchCount == 0 {
+ matchCount = 1
+ }
+ endPos, pos := 0, 0
+ for matchCount > 0 && pos != -1 {
+ if pos > 0 {
+ s = s[pos+1:]
+ endPos++
+ }
+ pos = strings.IndexByte(s, char)
+ endPos += pos
+ matchCount--
+ }
+ return endPos
+}
diff --git a/utils_bench_test.go b/utils_bench_test.go
new file mode 100644
index 00000000..3f77a4cf
--- /dev/null
+++ b/utils_bench_test.go
@@ -0,0 +1,122 @@
+// โก๏ธ Fiber is an Express inspired web framework written in Go with โ๏ธ
+// ๐ Github Repository: https://github.com/gofiber/fiber
+// ๐ API Documentation: https://docs.gofiber.io
+
+package fiber
+
+import (
+ "testing"
+)
+
+// go test -v ./... -run=^$ -bench=Benchmark_CC_ -benchmem -count=3
+
+// func Benchmark_Utils_assertEqual(b *testing.B) {
+// // TODO
+// }
+
+func Benchmark_Utils_getGroupPath(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _ = getGroupPath("/v1", "/")
+ _ = getGroupPath("/v1", "/api")
+ _ = getGroupPath("/v1", "/api/register/:project")
+ _ = getGroupPath("/v1/long/path/john/doe", "/why/this/name/is/so/awesome")
+ }
+}
+
+func Benchmark_Utils_getMIME(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _ = getMIME(".json")
+ _ = getMIME(".xml")
+ _ = getMIME("xml")
+ _ = getMIME("json")
+ }
+}
+
+// func Benchmark_Utils_getArgument(b *testing.B) {
+// // TODO
+// }
+
+// func Benchmark_Utils_parseTokenList(b *testing.B) {
+// // TODO
+// }
+
+func Benchmark_Utils_getString(b *testing.B) {
+ raw := []byte("Hello, World!")
+ for n := 0; n < b.N; n++ {
+ _ = getString(raw)
+ }
+}
+
+func Benchmark_Utils_getStringImmutable(b *testing.B) {
+ raw := []byte("Hello, World!")
+ for n := 0; n < b.N; n++ {
+ _ = getStringImmutable(raw)
+ }
+}
+
+func Benchmark_Utils_getBytes(b *testing.B) {
+ raw := "Hello, World!"
+ for n := 0; n < b.N; n++ {
+ _ = getBytes(raw)
+ }
+}
+
+func Benchmark_Utils_getBytesImmutable(b *testing.B) {
+ raw := "Hello, World!"
+ for n := 0; n < b.N; n++ {
+ _ = getBytesImmutable(raw)
+ }
+}
+
+func Benchmark_Utils_methodINT(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _ = methodINT[MethodGet]
+ _ = methodINT[MethodHead]
+ _ = methodINT[MethodPost]
+ _ = methodINT[MethodPut]
+ _ = methodINT[MethodPatch]
+ _ = methodINT[MethodDelete]
+ _ = methodINT[MethodConnect]
+ _ = methodINT[MethodOptions]
+ _ = methodINT[MethodTrace]
+ }
+}
+
+func Benchmark_Utils_statusMessage(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _ = statusMessage[100]
+ _ = statusMessage[304]
+ _ = statusMessage[423]
+ _ = statusMessage[507]
+ }
+}
+
+func Benchmark_Utils_extensionMIME(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _ = extensionMIME[".json"]
+ _ = extensionMIME["json"]
+ _ = extensionMIME["xspf"]
+ _ = extensionMIME[".xspf"]
+ _ = extensionMIME["avi"]
+ _ = extensionMIME[".avi"]
+ }
+}
+
+// func Benchmark_Utils_getParams(b *testing.B) {
+// // TODO
+// }
+
+// func Benchmark_Utils_matchParams(b *testing.B) {
+// // TODO
+// }
+
+func Benchmark_Utils_getTrimmedParam(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ _ = getTrimmedParam(":param")
+ _ = getTrimmedParam(":param?")
+ }
+}
+
+// func Benchmark_Utils_getCharPos(b *testing.B) {
+// // TODO
+// }
diff --git a/utils_test.go b/utils_test.go
new file mode 100644
index 00000000..92408828
--- /dev/null
+++ b/utils_test.go
@@ -0,0 +1,255 @@
+// โก๏ธ Fiber is an Express inspired web framework written in Go with โ๏ธ
+// ๐ Github Repository: https://github.com/gofiber/fiber
+// ๐ API Documentation: https://docs.gofiber.io
+
+package fiber
+
+import (
+ "fmt"
+ "testing"
+)
+
+// func Test_Utils_assertEqual(t *testing.T) {
+// // TODO
+// }
+
+// func Test_Utils_setETag(t *testing.T) {
+// // TODO
+// }
+
+func Test_Utils_getGroupPath(t *testing.T) {
+ res := getGroupPath("/v1", "/")
+ assertEqual(t, "/v1", res)
+
+ res = getGroupPath("/v1", "/")
+ assertEqual(t, "/v1", res)
+
+ res = getGroupPath("/", "/")
+ assertEqual(t, "/", res)
+
+ res = getGroupPath("/v1/api/", "/")
+ assertEqual(t, "/v1/api/", res)
+}
+
+func Test_Utils_getMIME(t *testing.T) {
+ res := getMIME(".json")
+ assertEqual(t, "application/json", res)
+
+ res = getMIME(".xml")
+ assertEqual(t, "application/xml", res)
+
+ res = getMIME("xml")
+ assertEqual(t, "application/xml", res)
+
+ res = getMIME("json")
+ assertEqual(t, "application/json", res)
+}
+
+// func Test_Utils_getArgument(t *testing.T) {
+// // TODO
+// }
+
+// func Test_Utils_parseTokenList(t *testing.T) {
+// // TODO
+// }
+
+func Test_Utils_getString(t *testing.T) {
+ res := getString([]byte("Hello, World!"))
+ assertEqual(t, "Hello, World!", res)
+}
+
+func Test_Utils_getStringImmutable(t *testing.T) {
+ res := getStringImmutable([]byte("Hello, World!"))
+ assertEqual(t, "Hello, World!", res)
+}
+
+func Test_Utils_getBytes(t *testing.T) {
+ res := getBytes("Hello, World!")
+ assertEqual(t, []byte("Hello, World!"), res)
+}
+
+func Test_Utils_getBytesImmutable(t *testing.T) {
+ res := getBytesImmutable("Hello, World!")
+ assertEqual(t, []byte("Hello, World!"), res)
+}
+
+func Test_Utils_methodINT(t *testing.T) {
+ res := methodINT[MethodGet]
+ assertEqual(t, 0, res)
+ res = methodINT[MethodHead]
+ assertEqual(t, 1, res)
+ res = methodINT[MethodPost]
+ assertEqual(t, 2, res)
+ res = methodINT[MethodPut]
+ assertEqual(t, 3, res)
+ res = methodINT[MethodPatch]
+ assertEqual(t, 4, res)
+ res = methodINT[MethodDelete]
+ assertEqual(t, 5, res)
+ res = methodINT[MethodConnect]
+ assertEqual(t, 6, res)
+ res = methodINT[MethodOptions]
+ assertEqual(t, 7, res)
+ res = methodINT[MethodTrace]
+ assertEqual(t, 8, res)
+}
+
+func Test_Utils_statusMessage(t *testing.T) {
+ res := statusMessage[102]
+ assertEqual(t, "Processing", res)
+
+ res = statusMessage[303]
+ assertEqual(t, "See Other", res)
+
+ res = statusMessage[404]
+ assertEqual(t, "Not Found", res)
+
+ res = statusMessage[507]
+ assertEqual(t, "Insufficient Storage", res)
+
+}
+
+func Test_Utils_extensionMIME(t *testing.T) {
+ res := extensionMIME[".html"]
+ assertEqual(t, "text/html", res)
+
+ res = extensionMIME["html"]
+ assertEqual(t, "text/html", res)
+
+ res = extensionMIME[".msp"]
+ assertEqual(t, "application/octet-stream", res)
+
+ res = extensionMIME["msp"]
+ assertEqual(t, "application/octet-stream", res)
+}
+
+// func Test_Utils_getParams(t *testing.T) {
+// // TODO
+// }
+
+func Test_Utils_matchParams(t *testing.T) {
+ type testparams struct {
+ url string
+ params []string
+ match bool
+ }
+ testCase := func(r string, cases []testparams) {
+ parser := getParams(r)
+ for _, c := range cases {
+ params, match := parser.getMatch(c.url, false)
+ assertEqual(t, c.params, params, fmt.Sprintf("route: '%s', url: '%s'", r, c.url))
+ assertEqual(t, c.match, match, fmt.Sprintf("route: '%s', url: '%s'", r, c.url))
+ }
+ }
+ testCase("/api/v1/:param/*", []testparams{
+ {url: "/api/v1/entity", params: []string{"entity", ""}, match: true},
+ {url: "/api/v1/entity/", params: []string{"entity", ""}, match: true},
+ {url: "/api/v1/entity/1", params: []string{"entity", "1"}, match: true},
+ {url: "/api/v", params: nil, match: false},
+ {url: "/api/v2", params: nil, match: false},
+ {url: "/api/v1/", params: nil, match: false},
+ })
+ testCase("/api/v1/:param?", []testparams{
+ {url: "/api/v1", params: []string{""}, match: true},
+ {url: "/api/v1/", params: []string{""}, match: true},
+ {url: "/api/v1/optional", params: []string{"optional"}, match: true},
+ {url: "/api/v", params: nil, match: false},
+ {url: "/api/v2", params: nil, match: false},
+ {url: "/api/xyz", params: nil, match: false},
+ })
+ testCase("/api/v1/*", []testparams{
+ {url: "/api/v1", params: []string{""}, match: true},
+ {url: "/api/v1/", params: []string{""}, match: true},
+ {url: "/api/v1/entity", params: []string{"entity"}, match: true},
+ {url: "/api/v1/entity/1/2", params: []string{"entity/1/2"}, match: true},
+ {url: "/api/v", params: nil, match: false},
+ {url: "/api/v2", params: nil, match: false},
+ {url: "/api/abc", params: nil, match: false},
+ })
+ testCase("/api/v1/:param", []testparams{
+ {url: "/api/v1/entity", params: []string{"entity"}, match: true},
+ {url: "/api/v1/entity/8728382", params: nil, match: false},
+ {url: "/api/v1", params: nil, match: false},
+ {url: "/api/v1/", params: nil, match: false},
+ })
+ testCase("/api/v1/const", []testparams{
+ {url: "/api/v1/const", params: []string{}, match: true},
+ {url: "/api/v1", params: nil, match: false},
+ {url: "/api/v1/", params: nil, match: false},
+ {url: "/api/v1/something", params: nil, match: false},
+ })
+ testCase("/api/v1/:param/abc/*", []testparams{
+ {url: "/api/v1/well/abc/wildcard", params: []string{"well", "wildcard"}, match: true},
+ {url: "/api/v1/well/abc/", params: []string{"well", ""}, match: true},
+ {url: "/api/v1/well/abc", params: []string{"well", ""}, match: true},
+ {url: "/api/v1/well/ttt", params: nil, match: false},
+ })
+ testCase("/api/:day/:month?/:year?", []testparams{
+ {url: "/api/1", params: []string{"1", "", ""}, match: true},
+ {url: "/api/1/", params: []string{"1", "", ""}, match: true},
+ {url: "/api/1/2", params: []string{"1", "2", ""}, match: true},
+ {url: "/api/1/2/3", params: []string{"1", "2", "3"}, match: true},
+ {url: "/api/", params: nil, match: false},
+ })
+ testCase("/api/*", []testparams{
+ {url: "/api/", params: []string{""}, match: true},
+ {url: "/api/joker", params: []string{"joker"}, match: true},
+ {url: "/api", params: []string{""}, match: true},
+ {url: "/api/v1/entity", params: []string{"v1/entity"}, match: true},
+ {url: "/api2/v1/entity", params: nil, match: false},
+ {url: "/api_ignore/v1/entity", params: nil, match: false},
+ })
+ testCase("/api/*/:param?", []testparams{
+ {url: "/api/", params: []string{"", ""}, match: true},
+ {url: "/api/joker", params: []string{"joker", ""}, match: true},
+ {url: "/api/joker/batman", params: []string{"joker", "batman"}, match: true},
+ {url: "/api/joker/batman/robin", params: []string{"joker/batman", "robin"}, match: true},
+ {url: "/api/joker/batman/robin/1", params: []string{"joker/batman/robin", "1"}, match: true},
+ {url: "/api", params: []string{"", ""}, match: true},
+ })
+ testCase("/api/*/:param", []testparams{
+ {url: "/api/test/abc", params: []string{"test", "abc"}, match: true},
+ {url: "/api/joker/batman", params: []string{"joker", "batman"}, match: true},
+ {url: "/api/joker/batman/robin", params: []string{"joker/batman", "robin"}, match: true},
+ {url: "/api/joker/batman/robin/1", params: []string{"joker/batman/robin", "1"}, match: true},
+ {url: "/api", params: nil, match: false},
+ })
+ testCase("/api/*/:param/:param2", []testparams{
+ {url: "/api/test/abc", params: nil, match: false},
+ {url: "/api/joker/batman", params: nil, match: false},
+ {url: "/api/joker/batman/robin", params: []string{"joker", "batman", "robin"}, match: true},
+ {url: "/api/joker/batman/robin/1", params: []string{"joker/batman", "robin", "1"}, match: true},
+ {url: "/api/joker/batman/robin/1/2", params: []string{"joker/batman/robin", "1", "2"}, match: true},
+ {url: "/api", params: nil, match: false},
+ })
+ testCase("/", []testparams{
+ {url: "/api", params: nil, match: false},
+ {url: "", params: []string{}, match: true},
+ {url: "/", params: []string{}, match: true},
+ })
+ testCase("/config/abc.json", []testparams{
+ {url: "/config/abc.json", params: []string{}, match: true},
+ {url: "config/abc.json", params: nil, match: false},
+ {url: "/config/efg.json", params: nil, match: false},
+ {url: "/config", params: nil, match: false},
+ })
+ testCase("/config/*.json", []testparams{
+ {url: "/config/abc.json", params: []string{"abc.json"}, match: true},
+ {url: "/config/efg.json", params: []string{"efg.json"}, match: true},
+ //{url: "/config/efg.csv", params: nil, match: false},// doesn`t work, current: params: "efg.csv", true
+ {url: "config/abc.json", params: nil, match: false},
+ {url: "/config", params: nil, match: false},
+ })
+ testCase("/xyz", []testparams{
+ {url: "xyz", params: nil, match: false},
+ {url: "xyz/", params: nil, match: false},
+ })
+}
+
+// func Test_Utils_getTrimmedParam(t *testing.T) {
+// // TODO
+// }
+
+// func Test_Utils_getCharPos(t *testing.T) {
+// // TODO
+// }