From 43bcac2031540abf2d6347aa1e92177fad50cd1c Mon Sep 17 00:00:00 2001 From: Manu Mtz-Almeida Date: Sun, 31 May 2015 05:00:47 +0200 Subject: [PATCH] Updates README --- README.md | 318 ++++++++++++++++++++---------------------------------- 1 file changed, 115 insertions(+), 203 deletions(-) diff --git a/README.md b/README.md index 70bf978c..d4ceb82f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#Gin Web Framework [![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin) [![Coverage Status](https://coveralls.io/repos/gin-gonic/gin/badge.svg?branch=develop)](https://coveralls.io/r/gin-gonic/gin?branch=develop) +#Gin Web Framework [![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin) [![Coverage Status](https://coveralls.io/repos/gin-gonic/gin/badge.svg?branch=master)](https://coveralls.io/r/gin-gonic/gin?branch=master) [![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin) [![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) @@ -9,108 +9,60 @@ Gin is a web framework written in Golang. It features a martini-like API with mu ``` $ cat test.go ``` -```go +```go package main -import ( - "net/http" - "github.com/gin-gonic/gin" -) +import "github.com/gin-gonic/gin" func main() { - router := gin.Default() - router.GET("/", func(c *gin.Context) { - c.String(http.StatusOK, "hello world") + r := gin.Default() + r.GET("/ping", func(c *gin.Context) { + c.String(200, "pong") }) - router.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - router.POST("/submit", func(c *gin.Context) { - c.String(http.StatusUnauthorized, "not authorized") - }) - router.PUT("/error", func(c *gin.Context) { - c.String(http.StatusInternalServerError, "an error happened :(") - }) - router.Run(":8080") + r.Run(":8080") // listen and serve on 0.0.0.0:8080 } ``` -##Gin is new, will it be supported? - -Yes, Gin is an internal tool of [Manu](https://github.com/manucorporat) and [Javi](https://github.com/javierprovecho) for many of our projects/start-ups. We developed it and we are going to continue using and improve it. - - -##Roadmap for v1.0 -- [ ] Ask our designer for a cool logo -- [ ] Add tons of unit tests -- [ ] Add internal benchmarks suite -- [ ] More powerful validation API -- [ ] Improve documentation -- [ ] Add Swagger support -- [x] Stable API -- [x] Improve logging system -- [x] Improve JSON/XML validation using bindings -- [x] Improve XML support -- [x] Flexible rendering system -- [x] Add more cool middlewares, for example redis caching (this also helps developers to understand the framework). -- [x] Continuous integration -- [x] Performance improments, reduce allocation and garbage collection overhead -- [x] Fix bugs - +##Gin v1. released +- [x] Zero allocation router. +- [x] Still the fastest http router and framework. From routing to writing. +- [x] Complete suite of unit tests +- [x] Battle tested +- [x] API frozen, new releases will not break your code. ## Start using it -Obviously, you need to have Git and Go already installed to run Gin. -Run this in your terminal +1. Download and install it: -``` +```sh go get github.com/gin-gonic/gin ``` -Then import it in your Go code: +2. Import it in your code: -``` +```go import "github.com/gin-gonic/gin" ``` ##API Examples -#### Create most basic PING/PONG HTTP endpoint -```go -package main - -import ( - "net/http" - "github.com/gin-gonic/gin" -) - -func main() { - r := gin.Default() - r.GET("/ping", func(c *gin.Context) { - c.String(http.StatusOK, "pong") - }) - - // Listen and serve on 0.0.0.0:8080 - r.Run(":8080") -} -``` - #### Using GET, POST, PUT, PATCH, DELETE and OPTIONS ```go func main() { - // Creates a gin router + logger and recovery (crash-free) middlewares - r := gin.Default() + // Creates a gin router with default middlewares: + // logger and recovery (crash-free) middlewares + router := gin.Default() - r.GET("/someGet", getting) - r.POST("/somePost", posting) - r.PUT("/somePut", putting) - r.DELETE("/someDelete", deleting) - r.PATCH("/somePatch", patching) - r.HEAD("/someHead", head) - r.OPTIONS("/someOptions", options) + router.GET("/someGet", getting) + router.POST("/somePost", posting) + router.PUT("/somePut", putting) + router.DELETE("/someDelete", deleting) + router.PATCH("/somePatch", patching) + router.HEAD("/someHead", head) + router.OPTIONS("/someOptions", options) // Listen and server on 0.0.0.0:8080 - r.Run(":8080") + router.Run(":8080") } ``` @@ -118,26 +70,24 @@ func main() { ```go func main() { - r := gin.Default() + router := gin.Default() // This handler will match /user/john but will not match neither /user/ or /user - r.GET("/user/:name", func(c *gin.Context) { - name := c.Params.ByName("name") - message := "Hello "+name - c.String(http.StatusOK, message) + router.GET("/user/:name", func(c *gin.Context) { + name := c.Param("name") + c.String(http.StatusOK, "Hello %s", name) }) // However, this one will match /user/john/ and also /user/john/send // If no other routers match /user/john, it will redirect to /user/join/ - r.GET("/user/:name/*action", func(c *gin.Context) { - name := c.Params.ByName("name") - action := c.Params.ByName("action") + router.GET("/user/:name/*action", func(c *gin.Context) { + name := c.Param("name") + action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) }) - // Listen and server on 0.0.0.0:8080 - r.Run(":8080") + router.Run(":8080") } ``` @@ -158,78 +108,32 @@ func main() { } ``` -###Form parameters +### Multipart/Urlencoded Form + ```go func main() { - r := gin.Default() - - // This will respond to urls like search?firstname=Jane&lastname=Doe - r.GET("/search", func(c *gin.Context) { - // You need to call ParseForm() on the request to receive url and form params first - c.Request.ParseForm() - - firstname := c.Request.Form.Get("firstname") - lastname := c.Request.Form.Get("lastname") + router := gin.Default() - message := "Hello "+ firstname + lastname - c.String(http.StatusOK, message) - }) - r.Run(":8080") + router.POST("/form_post", func(c *gin.Context) { + message := c.PostForm("message") + nick := c.DefaultPostForm("nick", "anonymous") + + c.JSON(200, gin.H{ + "status": "posted", + "message": message, + }) + }) + router.Run(":8080") } ``` -###Multipart Form -```go -package main - -import ( - "github.com/gin-gonic/gin" - "github.com/gin-gonic/gin/binding" -) - -type LoginForm struct { - User string `form:"user" binding:"required"` - Password string `form:"password" binding:"required"` -} - -func main() { - - r := gin.Default() - - r.POST("/login", func(c *gin.Context) { - - var form LoginForm - - // you can bind multipart form with explicit binding declaration: - // c.BindWith(&form, binding.Form) - // or you can simply use autobinding with Bind method: - c.Bind(&form) // in this case proper binding will be automatically selected - - if form.User == "user" && form.Password == "password" { - c.JSON(200, gin.H{"status": "you are logged in"}) - } else { - c.JSON(401, gin.H{"status": "unauthorized"}) - } - - }) - - r.Run(":8080") - -} -``` - -Test it with: -```bash -$ curl -v --form user=user --form password=password http://localhost:8080/login -``` - #### Grouping routes ```go func main() { - r := gin.Default() + router := gin.Default() // Simple group: v1 - v1 := r.Group("/v1") + v1 := router.Group("/v1") { v1.POST("/login", loginEndpoint) v1.POST("/submit", submitEndpoint) @@ -237,15 +141,14 @@ func main() { } // Simple group: v2 - v2 := r.Group("/v2") + v2 := router.Group("/v2") { v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) } - // Listen and server on 0.0.0.0:8080 - r.Run(":8080") + router.Run(":8080") } ``` @@ -354,6 +257,50 @@ func main() { } ``` + +###Multipart/Urlencoded binding +```go +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +type LoginForm struct { + User string `form:"user" binding:"required"` + Password string `form:"password" binding:"required"` +} + +func main() { + + router := gin.Default() + + router.POST("/login", func(c *gin.Context) { + // you can bind multipart form with explicit binding declaration: + // c.BindWith(&form, binding.Form) + // or you can simply use autobinding with Bind method: + var form LoginForm + c.Bind(&form) // in this case proper binding will be automatically selected + + if form.User == "user" && form.Password == "password" { + c.JSON(200, gin.H{"status": "you are logged in"}) + } else { + c.JSON(401, gin.H{"status": "unauthorized"}) + } + }) + + router.Run(":8080") + +} +``` + +Test it with: +```bash +$ curl -v --form user=user --form password=password http://localhost:8080/login +``` + + #### XML and JSON rendering ```go @@ -390,48 +337,41 @@ func main() { ``` ####Serving static files -Use Engine.ServeFiles(path string, root http.FileSystem): ```go func main() { - r := gin.Default() - r.Static("/assets", "./assets") + router := gin.Default() + router.Static("/assets", "./assets") + router.StaticFS("/more_static", http.Dir("my_file_system")) + router.StaticFile("/favicon.ico", "./resources/favicon.ico") // Listen and server on 0.0.0.0:8080 - r.Run(":8080") + router.Run(":8080") } ``` -Use the following example to serve static files at top level route of your domain. Files are being served from directory ./html. - -``` -r := gin.Default() -r.Use(static.Serve("/", static.LocalFile("html", false))) -``` - -Note: this will use `httpNotFound` instead of the Router's `NotFound` handler. - ####HTML rendering Using LoadHTMLTemplates() ```go func main() { - r := gin.Default() - r.LoadHTMLGlob("templates/*") - r.GET("/index", func(c *gin.Context) { - obj := gin.H{"title": "Main website"} - c.HTML(http.StatusOK, "index.tmpl", obj) + router := gin.Default() + router.LoadHTMLGlob("templates/*") + //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html") + router.GET("/index", func(c *gin.Context) { + c.HTML(http.StatusOK, "index.tmpl", gin.H{ + "title": "Main website", + }) }) - - // Listen and server on 0.0.0.0:8080 - r.Run(":8080") + router.Run(":8080") } ``` ```html -

+

{{ .title }}

+ ``` You can also use your own html template render @@ -440,41 +380,13 @@ You can also use your own html template render import "html/template" func main() { - r := gin.Default() + router := gin.Default() html := template.Must(template.ParseFiles("file1", "file2")) - r.SetHTMLTemplate(html) - - // Listen and server on 0.0.0.0:8080 - r.Run(":8080") + router.SetHTMLTemplate(html) + router.Run(":8080") } ``` -#####Using layout files with templates -```go -var baseTemplate = "main.tmpl" - -r.GET("/", func(c *gin.Context) { - r.SetHTMLTemplate(template.Must(template.ParseFiles(baseTemplate, "whatever.tmpl"))) - c.HTML(200, "base", data) -}) -``` -main.tmpl -```html -{{define "base"}} - - - - {{template "content" .}} - - -{{end}} -``` -whatever.tmpl -```html -{{define "content"}} -

Hello World!

-{{end}} -``` #### Redirects