pemrograman

17 Upload File

Upload File

Selain menerima input data berupa form dan query params, biasanya kita juga membutuhkan input data berupa file dari pengguna kita. Golang sebenarnya sudah memiliki fitur tersebut untuk menangani management upload file tersebut. Hal ini lebih memudahkan kita jika kita membuat web yang bisa menerima input file.

Saat kita ingin menerima upload file kita perlu melakukan parsing terlebih dahulu menggunakan Request.ParseMultipartFrom(size) atau bisa ambil data file tersebut menggunakan Request.FormFile(name) yang mana didalamnya secara otomatis melakukan parsing terlebih dahulu. Data-data yang terdapat pada package multipart seperti multipart.File sebagai representasi file-nya dan multipart.FileHeader sebagai informasi file-nya.

Contoh Implementasi Upload File

Buatlah template HTML seperti dibawah ini dengan nama file upload.form.html.

<!DOCTYPE html>
<html>
  <head>
    <title>Form</title>
  </head>
  <body>
    <form action="/upload" method="post" enctype="multipart/form-data">
      <label>Name : <input type="text" name="name"></label><br>
      <label>File : <input type="file" name="file"></label><br>
      <input type="submit" value="Upload">
    </form>
  </body>
</html>

Setelah itu kita buat halaman form upload handler seperti dibawah ini.

func UploadFormHandler(w http.ResponseWriter, r *http.Request) {
	err := myTemplates.ExecuteTemplate(w, "upload.form.html", nil)
	if err != nil {
		panic(err)
	}
}

Dan tambahkan fungsi handler tersebut pada router mux agar halaman terregister.

	mux.HandleFunc("/upload-form", UploadFormHandler)

Lakukan build ulang dan jalankan program maka harusnya akan muncul seperti tampilan dibawah ini.

tutorial golang redirect

Selanjutnya kita harus buat fungsi hanlder untuk menangkap POST yang mana proses ini yang akan menyimpan file yang di upload oleh pengguna.

func UploadHandler(w http.ResponseWriter, r *http.Request) {
	file, fileHeader, err := r.FormFile("file")
	if err != nil {
		panic(err)
	}
	fileDestination, err := os.Create("./resources/" + fileHeader.Filename)
	if err != nil {
		panic(err)
	}
	_, err = io.Copy(fileDestination, file)
	if err != nil {
		panic(err)
	}
	name := r.PostFormValue("name")
	myTemplates.ExecuteTemplate(w, "upload.success.html", map[string]interface{}{
		"Name": name,
		"File": "/static/" + fileHeader.Filename,
	})
}

Pastikan handler kita sudah didaftarkan pada router mux.

mux.HandleFunc("/upload", UploadHandler)

Setelah itu kita perlu buat juga template halaman setelah aksi upload tersebut akan mengembalikan ke halaman sukses buat file upload.success.html seperti dibawah ini.

<!DOCTYPE html>
<html>
  <head>
    <title>Success {{.Name}}</title>
  </head>
  <body>
    <h1>{{ .Name }}</h1>
    <a href="{{ .File }}">File</a>
  </body>
</html>

Pada tutorial sebelumnya disini, kita sudah melakukan setting agar file yang terdapat pada folder resources bisa terbaca pada path /static sehingga kita bisa mengakses file yang ada di folder resources dengan mengakses halaman path pada website seperti ini.

http://localhost:8080/static/<nama-file>

Jalankan program lalu kita coba upload file sembarang untuk melakukan testing seperti dibawah ini.

tutorial golang redirect

Tampilan setelah sukses dilakukan upload seperti dibawah ini.

tutorial golang redirect

Ini tampilan ketika file sudah dibuka karena path tersebut static dan diarahkan ke dalam folder resources.

tutorial golang redirect

Membuat Unit Test Upload

Bagaimana cara melakukan pengetesan dari fungsi handler upload tersebut? Berikut ini cara kita membuat unit test saat kita buat handler upload-nya.

//go:embed resources/tutorial-golang.webp
var uploadFileTest []byte

func TestUploadHandler(t *testing.T) {
	type args struct {
		name string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "success",
			args: args{
				name: "success upload",
			},
			want: "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Success success upload</title>\n  </head>\n  <body>\n    <h1>success upload</h1>\n    <a href=\"/static/contoh-upload.jpg\">File</a>\n  </body>\n</html>",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			body := new(bytes.Buffer)

			writer := multipart.NewWriter(body)
			writer.WriteField("name", tt.args.name)
			file, _ := writer.CreateFormFile("file", "contoh-upload.jpg")
			file.Write(uploadFileTest)
			writer.Close()

			request := httptest.NewRequest(http.MethodPost, "http://localhost/upload", body)
			request.Header.Set("Content-Type", writer.FormDataContentType())
			recorder := httptest.NewRecorder()
			UploadHandler(recorder, request)

			bodyResponse, _ := io.ReadAll(recorder.Result().Body)
			bodyString := string(bodyResponse)

			if !reflect.DeepEqual(bodyString, tt.want) {
				t.Errorf("response = %#v, want = %#v\n", bodyString, tt.want)
			}
		})
	}
}
comments powered by Disqus