How to upload files in Go step by step

When making a restful api uploading files is one of the key part.With go file upload is very easy to setup.This files may be images pdf or just some form data.In this post i am going to show you how easy it is to upload a file using go.

We are going to write a small program that  we will use to change a user profile image.

Project  Structure

Lets start with how our project structure will look like.

Note:i only show the important files.files that we use to save user on the database are not shown.

1
2
3
4
5
handlers
   handlers.go
helpers
   helpers.go
main.go

 Writing The Code to handle file upload

We are going to  write the code to retrieve and save our file from the request object.

The function takes the request object as a parameter and  return an filename and error(if any occurs).

As you know we are going to be sending our files as form data(multipart/form-data) thus we need a way to retrieve  the file  from our request object.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package helpers
import (
	"net/http"
	"os"
	"io"	
)
func FileUpload(r *http.Request) (string, error) {
//this function returns the filename(to save in database) of the saved file or an error if it occurs
	r.ParseMultipartForm(32 << 20)
//ParseMultipartForm parses a request body as multipart/form-data
	file, handler, err := r.FormFile("file")//retrieve the file from form data
	//replace file with the key your sent your image with 
	if err != nil {
		return "",err
	}
	defer file.Close() //close the file when we finish   
        //this is path which  we want to store the file
	f, err := os.OpenFile("path/to/save/image/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return "",err
	}
	defer f.Close()
	io.Copy(f, file)
        //here we save our file to our path
	return handler.Filename, nil
}

As you can see this function has two return types

  1. file_name-this is what you store to the database to use in retrieving the file later.
  2. error-when calling this function you check error and it nil

 Making an endpoint to handle our form request

Now that we have our function to save our file and image upload ready, its time to start using it.We are going to use the httprouter to handler our requests.

You can use a router of your choice like gorilla/mux but  i personally like httprouter due to its simplicity.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package handlers
import (
	"fmt"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"kenyaappexperts/database"
	"kenyaappexperts/models"
	"encoding/json"
	"kenyaappexperts/helpers"
)
func ChangeProfileImage(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    //a function to change a profile image
	userId := ps.ByName("user_id")
       //getting user_id from our request object
	var user models.User
	userData := database.DBCon.Where("id = ?", userId).First(&user)
     //reading the user whose image we want to change from the database
    if userData.RecordNotFound() {
        http.Error(w, "User Not Found", http.StatusNotFound)
        return
	} 
	imageName, err := helpers.FileUpload(r)
    //here we call the function we made to get the image and save it
	if err != nil {
	    http.Error(w, "Invalid Data", http.StatusBadRequest)
    	return
	    //checking whether any error occurred retrieving image
	}
	user.Image = imageName
    //if no error we we change the profile image for our user
    database.DBCon.Save(&user)
    w.Header().Set("Content-Type", "application/json")
    //we then return the new user details to update our user interface
    json.NewEncoder(w).Encode(user)
}

Now we have successfully created a function to accept request to change a user profile.The last step is to expose this function  and we will do this in the main.go file.

Connecting Our handler function with a router

In this final step we are going to to make a route that any time we want to change a user profiling we will be calling.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package main
import(
"github.com/julienschmidt/httprouter"
"net/http"
"kenyaappexperts/handlers"
)
func main(){
  router := httprouter.New()
  router.PUT("/change_profile/:user_id",handlers.ChangeProfileImage)
  err := http.ListenAndServe("0.0.0.0:3000", router)
  	if err != nil {
  		log.Fatal(err)
  	}
}

In this tutorial you should have noticed we have just retrieved the file without the form data.In my next tutorial i am going to show you how to do this.

That all you need to upload a file in golang. Happy coding .You can enroll for our free courses at Codesahara.

You can also read some of our previous post.Here

comments powered by Disqus