Skip to content

Instantly share code, notes, and snippets.

@aryomuzakki
Created March 25, 2024 17:51
Show Gist options
  • Save aryomuzakki/6e0d6c38081709c536e6ed97f0d16fdc to your computer and use it in GitHub Desktop.
Save aryomuzakki/6e0d6c38081709c536e6ed97f0d16fdc to your computer and use it in GitHub Desktop.
Example to handle image upload in go lang (with gorilla mux router). Save image as temp files, remove image, return image / serve image as response
/*
Handle image uploaded with multipart/form-data POST Request.
Save image to temp files,
image then removed after some process,
then return / serve the (processed) image as response.
Using gorilla mux router.
*/
package main
import (
"fmt"
"io"
"net/http"
"path/filepath"
"runtime"
"strings"
)
type ImageFile struct {
Name string
FullPath string
MimeType string
Bytes []byte
}
var (
_, b, _, _ = runtime.Caller(0)
RootPath = filepath.Join(filepath.Dir(b), "../")
tempFolderPath = filepath.Join(RootPath, "/temp-files")
)
func uploadHandler(w http.ResponseWriter, r *http.Request) {
// max total size 20mb
r.ParseMultipartForm(200 << 20)
f, h, err := r.FormFile("image")
if err != nil {
fmt.Printf("Error reading file of 'image' form data. Reason: %s\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
sourceImg, err := saveFile(f, h)
if err != nil {
fmt.Printf("Error saving file. Reason: %s\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// some processing here
removeFile(sourceImg.FullPath)
w.Header().Set("Content-Type", sourceImg.MimeType)
w.Header().Set("Content-Disposition", `inline; filename="`+removedExt(sourceImg.Name)+`.jpg"`)
w.Write(sourceImg.Bytes)
}
func removedExt(f string) string {
return strings.TrimSuffix(f, filepath.Ext(f))
}
func saveFile(f multipart.File, h *multipart.FileHeader) (ImageFile, error) {
defer f.Close()
tempFileName := fmt.Sprintf("uploaded-%s-*%s", removedExt(h.Filename), filepath.Ext(h.Filename))
tempFile, err := os.CreateTemp(tempFolderPath, tempFileName)
if err != nil {
errStr := fmt.Sprintf("Error in creating the file. Reason: %s\n", err)
fmt.Println(errStr)
return ImageFile{}, err
}
defer tempFile.Close()
filebytes, err := io.ReadAll(f)
if err != nil {
errStr := fmt.Sprintf("Error in reading the file buffer. Reason: %s\n", err)
fmt.Println(errStr)
return ImageFile{}, err
}
tempFile.Write(filebytes)
_, tFilename := filepath.Split(tempFile.Name())
imgFile := ImageFile{
Name: tFilename,
FullPath: tempFile.Name(),
MimeType: h.Header.Get("Content-Type"),
Bytes: filebytes,
}
return imgFile, nil
}
func removeFile(p string) bool {
err := os.Remove(p)
if err != nil {
fmt.Printf("\nCannot remove file. Reason: %s\n", err)
return false
}
return true
}
/*
Steps
1. In a new project folder, run `go mod init projectName`.
2. Add gorilla mux package by running `go get github.com/gorilla/mux`.
2. Copy 'main.go' and 'uploadHandler.go' to your folder.
3. Run `go run main.go` or with specified port from terminal `go run main.go --addr :5050`
*/
package main
import (
"flag"
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
)
func main() {
addr := flag.String("addr", ":5000", "server port")
flag.Parse()
r := mux.NewRouter()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("{\"message\": \"hello world\"}"))
}).Methods(http.MethodGet)
r.HandleFunc("/upload", uploadHandler).Methods(http.MethodPost)
fmt.Printf("server run on %s\n", *addr)
log.Fatal(http.ListenAndServe(*addr, r))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment