Browse Source

Merge pull request #784 from gin-gonic/readme

Add upload file example.
Javier Provecho Fernandez 9 years ago
parent
commit
cc2b75f830

+ 64 - 32
README.md

@@ -111,7 +111,7 @@ BenchmarkZeus_GithubAll 		| 2000 		| 944234 	| 300688 	| 2648
 
 
 ## API Examples
 ## API Examples
 
 
-#### Using GET, POST, PUT, PATCH, DELETE and OPTIONS
+### Using GET, POST, PUT, PATCH, DELETE and OPTIONS
 
 
 ```go
 ```go
 func main() {
 func main() {
@@ -137,7 +137,7 @@ func main() {
 }
 }
 ```
 ```
 
 
-#### Parameters in path
+### Parameters in path
 
 
 ```go
 ```go
 func main() {
 func main() {
@@ -162,7 +162,7 @@ func main() {
 }
 }
 ```
 ```
 
 
-#### Querystring parameters
+### Querystring parameters
 ```go
 ```go
 func main() {
 func main() {
 	router := gin.Default()
 	router := gin.Default()
@@ -229,34 +229,66 @@ func main() {
 id: 1234; page: 1; name: manu; message: this_is_great
 id: 1234; page: 1; name: manu; message: this_is_great
 ```
 ```
 
 
-### Another example: upload file
+### Upload files
 
 
-References issue [#548](https://github.com/gin-gonic/gin/issues/548).
+#### Single file
+
+References issue [#774](https://github.com/gin-gonic/gin/issues/774) and detail [example code](examples/upload-file/single).
 
 
 ```go
 ```go
 func main() {
 func main() {
 	router := gin.Default()
 	router := gin.Default()
+	router.POST("/upload", func(c *gin.Context) {
+		// single file
+		file, _ := c.FormFile("file")
+		log.Println(file.Filename)
+
+		c.String(http.StatusOK, fmt.Printf("'%s' uploaded!", file.Filename))
+	})
+	router.Run(":8080")
+}
+```
+
+How to `curl`:
+
+```bash
+curl -X POST http://localhost:8080/upload \
+  -F "file=@/Users/appleboy/test.zip" \
+  -H "Content-Type: multipart/form-data"
+```
 
 
+#### Multiple files
+
+See the detail [example code](examples/upload-file/multiple).
+
+```go
+func main() {
+	router := gin.Default()
 	router.POST("/upload", func(c *gin.Context) {
 	router.POST("/upload", func(c *gin.Context) {
+		// Multipart form
+		form, _ := c.MultipartForm()
+		files := form.File["upload[]"]
 
 
-	        file, header , err := c.Request.FormFile("upload")
-	        filename := header.Filename
-	        fmt.Println(header.Filename)
-	        out, err := os.Create("./tmp/"+filename+".png")
-	        if err != nil {
-	            log.Fatal(err)
-	        }
-	        defer out.Close()
-	        _, err = io.Copy(out, file)
-	        if err != nil {
-	            log.Fatal(err)
-	        }   
+		for _, file := range files {
+			log.Println(file.Filename)
+		}
+		c.String(http.StatusOK, fmt.Printf("%d files uploaded!", len(files)))
 	})
 	})
 	router.Run(":8080")
 	router.Run(":8080")
 }
 }
 ```
 ```
 
 
-#### Grouping routes
+How to `curl`:
+
+```bash
+curl -X POST http://localhost:8080/upload \
+  -F "upload[]=@/Users/appleboy/test1.zip" \
+  -F "upload[]=@/Users/appleboy/test2.zip" \
+  -H "Content-Type: multipart/form-data"
+```
+
+### Grouping routes
+
 ```go
 ```go
 func main() {
 func main() {
 	router := gin.Default()
 	router := gin.Default()
@@ -282,7 +314,7 @@ func main() {
 ```
 ```
 
 
 
 
-#### Blank Gin without middleware by default
+### Blank Gin without middleware by default
 
 
 Use
 Use
 
 
@@ -296,7 +328,7 @@ r := gin.Default()
 ```
 ```
 
 
 
 
-#### Using middleware
+### Using middleware
 ```go
 ```go
 func main() {
 func main() {
 	// Creates a router without any middleware by default
 	// Creates a router without any middleware by default
@@ -331,7 +363,7 @@ func main() {
 }
 }
 ```
 ```
 
 
-#### Model binding and validation
+### Model binding and validation
 
 
 To bind a request body into a type, use model binding. We currently support binding of JSON, XML and standard form values (foo=bar&boo=baz).
 To bind a request body into a type, use model binding. We currently support binding of JSON, XML and standard form values (foo=bar&boo=baz).
 
 
@@ -381,7 +413,7 @@ func main() {
 }
 }
 ```
 ```
 
 
-#### Bind Query String
+### Bind Query String
 
 
 See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292).
 See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292).
 
 
@@ -457,7 +489,7 @@ $ curl -v --form user=user --form password=password http://localhost:8080/login
 ```
 ```
 
 
 
 
-#### XML, JSON and YAML rendering
+### XML, JSON and YAML rendering
 
 
 ```go
 ```go
 func main() {
 func main() {
@@ -496,7 +528,7 @@ func main() {
 }
 }
 ```
 ```
 
 
-####Serving static files
+### Serving static files
 
 
 ```go
 ```go
 func main() {
 func main() {
@@ -510,7 +542,7 @@ func main() {
 }
 }
 ```
 ```
 
 
-####HTML rendering
+### HTML rendering
 
 
 Using LoadHTMLGlob() or LoadHTMLFiles()
 Using LoadHTMLGlob() or LoadHTMLFiles()
 
 
@@ -590,7 +622,7 @@ func main() {
 ```
 ```
 
 
 
 
-#### Redirects
+### Redirects
 
 
 Issuing a HTTP redirect is easy:
 Issuing a HTTP redirect is easy:
 
 
@@ -602,7 +634,7 @@ r.GET("/test", func(c *gin.Context) {
 Both internal and external locations are supported.
 Both internal and external locations are supported.
 
 
 
 
-#### Custom Middleware
+### Custom Middleware
 
 
 ```go
 ```go
 func Logger() gin.HandlerFunc {
 func Logger() gin.HandlerFunc {
@@ -642,7 +674,7 @@ func main() {
 }
 }
 ```
 ```
 
 
-#### Using BasicAuth() middleware
+### Using BasicAuth() middleware
 ```go
 ```go
 // simulate some private data
 // simulate some private data
 var secrets = gin.H{
 var secrets = gin.H{
@@ -681,7 +713,7 @@ func main() {
 ```
 ```
 
 
 
 
-#### Goroutines inside a middleware
+### Goroutines inside a middleware
 When starting inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy.
 When starting inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy.
 
 
 ```go
 ```go
@@ -713,7 +745,7 @@ func main() {
 }
 }
 ```
 ```
 
 
-#### Custom HTTP configuration
+### Custom HTTP configuration
 
 
 Use `http.ListenAndServe()` directly, like this:
 Use `http.ListenAndServe()` directly, like this:
 
 
@@ -740,7 +772,7 @@ func main() {
 }
 }
 ```
 ```
 
 
-#### Graceful restart or stop
+### Graceful restart or stop
 
 
 Do you want to graceful restart or stop your web server?
 Do you want to graceful restart or stop your web server?
 There are some ways this can be done.
 There are some ways this can be done.
@@ -771,7 +803,7 @@ An alternative to endless:
   - You should add/modify tests to cover your proposed code changes.
   - You should add/modify tests to cover your proposed code changes.
   - If your pull request contains a new feature, please document it on the README.
   - If your pull request contains a new feature, please document it on the README.
 
 
-## Example
+## Users
 
 
 Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework.
 Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework.
 
 

+ 39 - 0
examples/upload-file/multiple/main.go

@@ -0,0 +1,39 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+
+	"github.com/gin-gonic/gin"
+)
+
+func main() {
+	router := gin.Default()
+	router.Static("/", "./public")
+	router.POST("/upload", func(c *gin.Context) {
+		name := c.PostForm("name")
+		email := c.PostForm("email")
+
+		// Multipart form
+		form, _ := c.MultipartForm()
+		files := form.File["files"]
+
+		for _, file := range files {
+			// Source
+			src, _ := file.Open()
+			defer src.Close()
+
+			// Destination
+			dst, _ := os.Create(file.Filename)
+			defer dst.Close()
+
+			// Copy
+			io.Copy(dst, src)
+		}
+
+		c.String(http.StatusOK, fmt.Sprintf("Uploaded successfully %d files with fields name=%s and email=%s.", len(files), name, email))
+	})
+	router.Run(":8080")
+}

+ 17 - 0
examples/upload-file/multiple/public/index.html

@@ -0,0 +1,17 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>Multiple file upload</title>
+</head>
+<body>
+<h1>Upload multiple files with fields</h1>
+
+<form action="/upload" method="post" enctype="multipart/form-data">
+    Name: <input type="text" name="name"><br>
+    Email: <input type="email" name="email"><br>
+    Files: <input type="file" name="files" multiple><br><br>
+    <input type="submit" value="Submit">
+</form>
+</body>
+</html>

+ 34 - 0
examples/upload-file/single/main.go

@@ -0,0 +1,34 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+
+	"github.com/gin-gonic/gin"
+)
+
+func main() {
+	router := gin.Default()
+	router.Static("/", "./public")
+	router.POST("/upload", func(c *gin.Context) {
+		name := c.PostForm("name")
+		email := c.PostForm("email")
+
+		// Source
+		file, _ := c.FormFile("file")
+		src, _ := file.Open()
+		defer src.Close()
+
+		// Destination
+		dst, _ := os.Create(file.Filename)
+		defer dst.Close()
+
+		// Copy
+		io.Copy(dst, src)
+
+		c.String(http.StatusOK, fmt.Sprintf("File %s uploaded successfully with fields name=%s and email=%s.", file.Filename, name, email))
+	})
+	router.Run(":8080")
+}

+ 16 - 0
examples/upload-file/single/public/index.html

@@ -0,0 +1,16 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>Single file upload</title>
+</head>
+<body>
+<h1>Upload single file with fields</h1>
+
+<form action="/upload" method="post" enctype="multipart/form-data">
+    Name: <input type="text" name="name"><br>
+    Email: <input type="email" name="email"><br>
+    Files: <input type="file" name="file"><br><br>
+    <input type="submit" value="Submit">
+</form>
+</body>