Image Uploads in a React/Go Stack — Part 3

James Howard
2 min readApr 3, 2024

--

This is the final part of this seriesand follows on from part 1 and part 2. Now that we have a functional API endpoint, the next step is to connect up the front-end and get it working end to end.

Get Image from the API

Before we start this, we’ll need to do a little bit more work in the API since being able to display the image is probably a pre-prequisite for uploading an image.

This is a fairly simple operation. Just read the file from the filesystem and return the data, it’s MIME type and any possible errors. Remember that this is going to be temporary as ultimately we should put these files on a CDN and serve them directly from there but we will need to know the MIME type. This can be detected reasonably reliably from the file contents which will serve our purposes for now.

func GetUserProfileImage(userID uint) ([]byte, error, string) {
imageFileName := os.Getenv("PROFILE_IMAGE_STORAGE") + "/profile_image_" + strconv.Itoa(int(userID))

mimeType := ""
byteFile, err := os.ReadFile(imageFileName)
if err == nil {
mimeType = http.DetectContentType(byteFile)
}
return byteFile, err, mimeType
}

Then, in our controller, we need to get the user ID for the image, and call the profile image function before outputting the data.

func GetUserProfileImage(c *gin.Context) {
userID, _ := strconv.Atoi(c.Param("userID"))
byteFile, err, mimeType := models.GetUserProfileImage(uint(userID))
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"message": "No profile image found", "code": errors.UserSaveNoContent})
}

c.Data(http.StatusOK, mimeType, byteFile)
}

Submitting Images

To keep things simple, I’ve avoided using a form here and just constructed a POST response in code which is called from the onClick event of the save button. You could set up a form to submit this but I don’t think it’s worth the trouble.

function saveImages() {
const localImages = images as ImageListType

if (localImages.length > 0) {
let localImage = localImages[0]
let url = Helpers.GetAPIURL("api/admin/user/profile_image")
let token = cookies["token"];
const config = {
headers: {
"authorization": `Bearer ${token}`,
"content-type": "multipart/form-data"
}
};

let bodyData = Object()
let formData = new FormData()
formData.append("imageFile", localImage.file!)

axios.post(url, formData, config)
.then(function (response) {
clearErrors()
let responseData = parseUserDetails(response);

onCompleteCallback(responseData)
})
.catch(function (response) {
handleResponseErrors(response)
})
}
}

So this is all pretty simple stuff. Set up the http header including the bearer token and make sure the content type is set up as multipart/form-data. In this case, all I’m submitting is the imageFile but we could also add in other fields if we needed to.

You can see that there are some other functions called here for parsing responses and errors and also to handle the completion of the submission. The details of this are beyond the brief of submitting image data so we can leave it here.

--

--