Skip to content

Commit

Permalink
upload download file using multipart/form-data
Browse files Browse the repository at this point in the history
  • Loading branch information
Le Minh Tan committed Jul 29, 2021
1 parent a00bf4d commit c048aac
Show file tree
Hide file tree
Showing 5 changed files with 890 additions and 0 deletions.
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/dutroctu/go-webservice/database"
"github.com/dutroctu/go-webservice/product"
"github.com/dutroctu/go-webservice/receipt"
_ "github.com/go-sql-driver/mysql"
)

Expand All @@ -24,6 +25,7 @@ const apiBasePath = "/api"

func main() {
database.SetupDatabase()
receipt.SetupRoutes(apiBasePath)
product.SetupRoutes(apiBasePath)

http.ListenAndServe(":5000", nil)
Expand Down
26 changes: 26 additions & 0 deletions receipt/receipt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package receipt

import (
"io/ioutil"
"path/filepath"
"time"
)

var ReceiptDirectory string = filepath.Join("uploads")

type Receipt struct {
ReceiptName string `json:"name"`
UploadDate time.Time `json:"uploadDate"`
}

func GetReceipts() ([]Receipt, error) {
receipts := make([]Receipt, 0)
files, err := ioutil.ReadDir(ReceiptDirectory)
if err != nil {
return nil, err
}
for _, f := range files {
receipts = append(receipts, Receipt{ReceiptName: f.Name(), UploadDate: f.ModTime()})
}
return receipts, nil
}
95 changes: 95 additions & 0 deletions receipt/receipt.service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package receipt

import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/dutroctu/go-webservice/cors"
)

const receiptPath = "receipts"

func handleReceipts(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
receiptList, err := GetReceipts()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
j, err := json.Marshal(receiptList)
if err != nil {
log.Fatal(err)
}
_, err = w.Write(j)
if err != nil {
log.Fatal(err)
}
case http.MethodPost:
r.ParseMultipartForm(5 << 20) //5Mb
file, handler, err := r.FormFile("receipt")
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
defer file.Close()
f, err := os.OpenFile(filepath.Join(ReceiptDirectory, handler.Filename),
os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
defer f.Close()
io.Copy(f, file)
w.WriteHeader(http.StatusCreated)

case http.MethodOptions:
return
default:
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
}

func SetupRoutes(apiBasePath string) {
receiptHandler := http.HandlerFunc(handleReceipts)
downloadHandler := http.HandlerFunc(handleDownload)
http.Handle(fmt.Sprintf("%s/%s", apiBasePath, receiptPath), cors.Middleware(receiptHandler))
http.Handle(fmt.Sprintf("%s/%s/", apiBasePath, receiptPath), cors.Middleware(downloadHandler))
}

func handleDownload(w http.ResponseWriter, r *http.Request) {
urlPathSegments := strings.Split(r.URL.Path, fmt.Sprintf("%s/", receiptPath))
if len(urlPathSegments[1:]) > 1 {
w.WriteHeader(http.StatusBadRequest)
return
}
fileName := urlPathSegments[1:][0]
file, err := os.Open(filepath.Join(ReceiptDirectory, fileName))
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
defer file.Close()
fHeader := make([]byte, 512)
file.Read(fHeader)
fContentType := http.DetectContentType(fHeader)
stat, err := file.Stat()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
fSize := strconv.FormatInt(stat.Size(), 10)
w.Header().Set("Content-Disposition", "attachment; filename="+fileName)
w.Header().Set("Content-Type", fContentType)
w.Header().Set("Content-Length", fSize)
file.Seek(0, 0)
io.Copy(w, file)
}
Loading

0 comments on commit c048aac

Please sign in to comment.