How to upload files with Golang and Ajax?

gcdcoder profile image Gustavo Castillo Updated on ・3 min read

Uploading file(s) is a common functionality that we want to use in our websites, it could be for user's profile avatar, an image gallery, a cover post and so on, but What if you want to do it by using Ajax. Let's see how I solved this problem.

First of all let me give you the project structure:


Then let's create the index.html file inside public folder and write the following code:

<!DOCTYPE html>
<html lang="es">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, 
    user-scalable=no, initial-scale=1.0, maximum-scale=1.0,
    <link rel="stylesheet" 
    <link rel="stylesheet" href="styles.css">
    <title>File upload using Ajax</title>
    <form action="/upload" method="post" enctype="multipart/form-data" class="uploadForm">
        <input class="uploadForm__input" type="file" name="file" id="inputFile" accept="image/*">
        <label class="uploadForm__label" for="inputFile">
            <i class="fa fa-upload uploadForm__icon"></i> Select a file
    <div class="notification" id="alert"></div>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="api.js"></script>
    <script src="app.js"></script>

Let's add some basic CSS styles and create the styles.css file inside public folder:

body {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100vh;    
    font-family: Verdana, Geneva, Tahoma, sans-serif;

.uploadForm__label {
    display: flex;
    align-items: center;
    justify-content: center;

.uploadForm {
    width: 600px;
    max-width: 600px;
    height: 300px;
    flex-direction: column;    
    border: 2px dashed gray;
    font-family: inherit;

.uploadForm__input {
    display: none;

.uploadForm__label {
    border: 1px solid gray;
    padding: .5em 2em;
    color: deepskyblue;
    transition: transform .4s;
    flex-direction: column;

.uploadForm__label:hover {
    cursor: pointer;
    transform: scale(1.01);
    box-shadow: grey 2px 2px 10px;

.uploadForm__icon {
    font-size: 1.8em;

.notification {    
    display: none;    

.error {
    right: 30px;
    z-index: 10;
    width: 300px;
    bottom: 40px;
    padding: 1em;
    height: auto;
    text-align: center;
    display: block;
    position: fixed;
    font-family: inherit;
    animation: alert .8s forwards;

.notification.success {
    background: #D9EDF7;
    color: #31709C;

.notification.error {
    background: #F2DEDE;
    color: #B24842;

@keyframes alert {
    0% {
        opacity: 0;
        bottom: -40px;

    100% {
        opacity: 1;
        bottom: 40px;

Next let's create the app.js file inside public folder too and write the following code:

(function (d, axios) {
    "use strict";
    var inputFile = d.querySelector("#inputFile");
    var divNotification = d.querySelector("#alert");

    inputFile.addEventListener("change", addFile);

    function addFile(e) {
        var file = e.target.files[0]

    function upload(file) {
        var formData = new FormData()
        formData.append("file", file)
        post("/upload", formData)

    function onResponse(response) {
        var className = (response.status !== 400) ? "success" : "error";
        divNotification.innerHTML = response.data;
        setTimeout(function() {
        }, 3000);
})(document, axios)

Finally we need to create api.js file one more time inside public folder and write this code:

"use strict";

function post(url, data) {
    return axios.post(url, data)
        .then(function (response) {
            return response;
        }).catch(function (error) {
            return error.response;

Well, after all this let's finally write some Go code. I'm going to start by creating the file.go file inside controllers folder and write the following:

package controllers

import (

// UploadFile uploads a file to the server
func UploadFile(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Redirect(w, r, "/", http.StatusSeeOther)

    file, handle, err := r.FormFile("file")
    if err != nil {
        fmt.Fprintf(w, "%v", err)
    defer file.Close()

    mimeType := handle.Header.Get("Content-Type")
    switch mimeType {
    case "image/jpeg":
        saveFile(w, file, handle)
    case "image/png":
        saveFile(w, file, handle)
        jsonResponse(w, http.StatusBadRequest, "The format file is not valid.")

func saveFile(w http.ResponseWriter, file multipart.File, handle *multipart.FileHeader) {
    data, err := ioutil.ReadAll(file)
    if err != nil {
        fmt.Fprintf(w, "%v", err)

    err = ioutil.WriteFile("./files/"+handle.Filename, data, 0666)
    if err != nil {
        fmt.Fprintf(w, "%v", err)
    jsonResponse(w, http.StatusCreated, "File uploaded successfully!.")

func jsonResponse(w http.ResponseWriter, code int, message string) {
    w.Header().Set("Content-Type", "application/json")
    fmt.Fprint(w, message)

As our final step let's create the main.go file in your root directory and use the file package like so:

package main

import (

        // Note this is my path according to my GOPATH, chage it according to yours.

func main() {
    http.Handle("/", http.FileServer(http.Dir("./public")))
    http.HandleFunc("/upload", controllers.UploadFile)
    http.ListenAndServe(":8080", nil)


  1. I'm not handling validation (you should do it), but it should work like a charm.
  2. I'm using my GOPATH root, please change according to yours.
  3. Keep learning and happy code :).

Posted on Aug 16 '17 by:

gcdcoder profile

Gustavo Castillo


I'm a web developer I won't fix your computer >:(


markdown guide

@ajinkya how would the routine looks with io.Copy ?


case "image/jpeg":
saveFile(w, file, handle)
case "image/png":
saveFile(w, file, handle)

can be ->

case "image/jpeg", "image/png":
saveFile(w, file, handle)