Using Gin to get an uploaded file
I think your question is "Using Gin, how do I get an uploaded file?". Most developers don't upload files with JSON encoding, which could be done but requires the file to be included as a base64 string (and increases the file size about 33%).
The common (and more efficient) practice is to upload the file using the "multipart/form-data" encoding. The code that others provided file, header, err := c.Request.FormFile("file")
works, but that hijacks the underlining "net/http" package that Gin extends.
My recommendation is to use ShouldBind
, but you can also use the FormFile
or MultipartForm
methods provided by the Gin package.
Examples below. Similar (but less detailed) explanations are also offered on the Gin page https://github.com/gin-gonic/gin#model-binding-and-validation and https://github.com/gin-gonic/gin#upload-files.
Upload one file
Clients
HTML
<form action="/upload" method="POST">
<input type="file" name="file">
<input type="submit">
</form>
Curl
curl -X POST http://localhost:8080/upload \
-F "file=../path-to-file/file.zip" \
-H "Content-Type: multipart/form-data"
Server
Go
package main
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
"io/ioutil"
)
type Form struct {
File *multipart.FileHeader `form:"file" binding:"required"`
}
func main() {
router := gin.Default()
// Set a lower memory limit for multipart forms (default is 32 MiB)
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// Using `ShouldBind`
// --------------------
var form Form
_ := c.ShouldBind(&form)
// Get raw file bytes - no reader method
// openedFile, _ := form.File.Open()
// file, _ := ioutil.ReadAll(openedFile)
// Upload to disk
// `form.File` has io.reader method
// c.SaveUploadedFile(form.File, path)
// --------------------
// Using `FormFile`
// --------------------
// formFile, _ := c.FormFile("file")
// Get raw file bytes - no reader method
// openedFile, _ := formFile.Open()
// file, _ := ioutil.ReadAll(openedFile)
// Upload to disk
// `formFile` has io.reader method
// c.SaveUploadedFile(formFile, path)
// --------------------
c.String(http.StatusOK, "Files uploaded")
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
Upload multiple files
Clients
HTML
<form action="/upload" method="POST" multiple="multiple">
<input type="file" name="files">
<input type="submit">
</form>
Curl
curl -X POST http://localhost:8080/upload \
-F "files=../path-to-file/file1.zip" \
-F "files=../path-to-file/file2.zip" \
-H "Content-Type: multipart/form-data"
Server
Go
package main
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
"io/ioutil"
)
type Form struct {
Files []*multipart.FileHeader `form:"files" binding:"required"`
}
func main() {
router := gin.Default()
// Set a lower memory limit for multipart forms (default is 32 MiB)
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// Using `ShouldBind`
// --------------------
var form Form
_ := c.ShouldBind(&form)
// for _, formFile := range form.Files {
// Get raw file bytes - no reader method
// openedFile, _ := formFile.Open()
// file, _ := ioutil.ReadAll(openedFile)
// Upload to disk
// `formFile` has io.reader method
// c.SaveUploadedFile(formFile, path)
// }
// --------------------
// Using `MultipartForm`
// --------------------
// form, _ := c.MultipartForm()
// formFiles, _ := form["files[]"]
// for _, formFile := range formFiles {
// Get raw file bytes - no reader method
// openedFile, _ := formFile.Open()
// file, _ := ioutil.ReadAll(openedFile)
// Upload to disk
// `formFile` has io.reader method
// c.SaveUploadedFile(formFile, path)
// }
// --------------------
c.String(http.StatusOK, "Files uploaded")
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}