File upload using Gin

This post is my third post covering concepts of Gin , the HTTP web framework for Go. My previous post are:

In the RESTful era, most of our requests and responses’ payloads are JSON. However, in some cases, you may want to upload a file instead. In this post I’m going to describe how to receive and save an uploaded file using Gin framework.

The most common way to upload a file in a web browser is via the html file upload element (<input type="file" />). To be able to let the server know that you’re uploading a file, the request’s Content-Type header must be set to multipart/form-data. Here’s an example function for sending a file to a server using ReactJS and Axios:

import Axios from 'axios';

uploadFile = (file) => {
  const formData = new FormData();
  formData.append('file', file);
  Axios.post('https://example.com/upload', formData, {
    headers: {
      'Content-Type': 'multipart/form-data',
    },
  }).then((resp) => {
    if (resp.status === 200) {
      console.log('File uploaded');
    }
  });
};

If everything goes fine, the file will be sent to the server. Now it’s time to get the file and save it some where in our server. Fortunately, Gin provides a very simply way to receive files. Gin’s Context argument (which all route handlers must have) has a FromFile method which helps you receive files from a multi-part content. Please take a look the following example:

import (
    "net/http"
    "path/filepath"

    "github.com/gin-gonic/gin"
    "github.com/google/uuid" // To generate random file names
)

func saveFileHandler(c *gin.Context) {
    file, err := c.FormFile("file")

    // The file cannot be received.
    if err != nil {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
            "message": "No file is received",
        })
        return
    }

    // Retrieve file information
    extension := filepath.Ext(file.Filename)
    // Generate random file name for the new uploaded file so it doesn't override the old file with same name
    newFileName := uuid.New().String() + extension

    // The file is received, so let's save it
    if err := c.SaveUploadedFile(file, "/some/path/on/server/" + newFileName); err != nil {
        c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
            "message": "Unable to save the file",
        })
        return
    }

    // File saved successfully. Return proper result
    c.JSON(http.StatusOK, gin.H{
        "message": "Your file has been successfully uploaded."
    })
}

As you can see in the above code, saveFileHandler is responsible for receiving and saving the file to the server. In line 10, we try to receive the uploaded file with the name file; then we check if the file is received successfully. To avoid conflicts, in line 23, we change the file name to a random string (UUID in this case). Finally, we attempt to save the file using Gin’s SaveUploadedFile method and check if the save is saved. To handle errors, we return proper responses if any errors occurred. If every goes well and we could save the file to our path, we return the 200 OK response to the client.

The above is a general example. You may want to validate the file you receive. In some cases, you just need to receive image files; so, file types should be validated. In addition, you may want to resize the received image before saving it.

How to enable CORS support in Gin

It’s about 3 months that I’m trying to do some real work in Go and my HTTP framework of choice is Gin.

After developing some REST APIs, I decided to create a frontend application to actually use them. When it comes to frontend development I usually choose ReactJS. Maybe I should write about why I like ReactJS over other frontend frameworks in the future ;)

When a client especially a web-based client wants to access an API, the server decides which clients are allowed to send requests. This is done by using called CORS which stands for Cross-origin resource sharing.

Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served.

For more information about CORS please check this Wikipedia article

You can manually add the required headers to each response using Gin’s Header method if you want:

func CustomHeaderAPI(c *gin.Context) {
    // Add CORS headers
    c.Header("Access-Control-Allow-Origin", "http://example.com")
    c.Header("Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, OPTIONS")

    // Prepare response
    c.JSON(http.StatusOK, gin.H{
        "message": "this response has custom headers"
    })
}

But it would be a pain in the neck to add the following lines of code to each API. To make things easier Gin supports middleware functions.

What are middleware functions? This is a good definition I found on the web:

Middleware functions are functions that have access to the request object ( req ), the response object ( res ), and the next function in the application’s request-response cycle.

You may create a middleware yourself to enable CORS support; but, we don’t want to reinvent the wheel! A group of nice people in the community has developed a library to enable CORS support in Gin. It’s called CORS gin’s middleware.

To install it:

go get github.com/gin-contrib/cors

After installed, simply import it:

import "github.com/gin-contrib/cors"

And start using it:

package main

import (
 "time"

 "github.com/gin-contrib/cors"
 "github.com/gin-gonic/gin"
)

func main() {
 router := gin.Default()
 // CORS for https://foo.com and https://github.com origins, allowing:
 // - PUT and PATCH methods
 // - Origin header
 // - Credentials share
 // - Preflight requests cached for 12 hours
 router.Use(cors.New(cors.Config{
  AllowOrigins:     []string{"https://foo.com"},
  AllowMethods:     []string{"PUT", "PATCH"},
  AllowHeaders:     []string{"Origin"},
  ExposeHeaders:    []string{"Content-Length"},
  AllowCredentials: true,
  AllowOriginFunc: func(origin string) bool {
   return origin == "https://github.com"
  },
  MaxAge: 12 * time.Hour,
 }))
 router.Run()
}

The above configuration is the most complete example of what capabilities the library gives you. However, you may don’t want to use them all. In fact, most of the projects’ CORS configuration are identical. To make it even simpler, cors package also has something called DefaultConfig which returns a generic default configuration mapped to localhost. In my opinion, the best way to use this library is to add your custom configurations to the DefaultConfig’s result. For example, here is my own configuration for a project:

router := gin.Default()
corsConfig := cors.DefaultConfig()

corsConfig.AllowOrigins = []string{"https://example.com"}
// To be able to send tokens to the server.
corsConfig.AllowCredentials = true

// OPTIONS method for ReactJS
corsConfig.AddAllowMethods("OPTIONS")

// Register the middleware
router.Use(cors.New(corsConfig))

Please support the library by star them on Github: https://github.com/gin-contrib/cors

I Hope it helps.

How to use custom HTTP methods in Go Gin framework

The Gin framework is probably the most popular Go framework for creating RESTful APIs. It lets you create a web app in a matter of minutes.

When it comes to RESTful APIs, HTTP methods and status codes become very important. It’s a best practice to divide your APIs’ functionalities with different HTTP methods. For example, the method POST is used when want to add something to the database while the verb PUT is used for updating an entity.

By some conventions, some developers prefer to use custom verbs like LIST, ASSIGN, LOGIN, and etc. as well. For instance, if a list of all categories need to be retrieved, instead of using the GET method, LIST can be used. Gin supports the most common HTTP methods by default. These methods are GET, POST, PUT, DELETE, HEAD, PATCH, and OPTIONS.

Here is an example of a very simple web API using Gin:

package main

import (
 "net/http"

 "github.com/gin-gonic/gin"
)

func main() {
 router := gin.Default()
 router.GET("/hello", sayHello)
 router.Run(":3000")
}

func sayHello(c *gin.Context) {
 c.JSON(http.StatusOK, gin.H{
  "message": "Hello!!",
 })
}

But what if you want to use some custom HTTP methods? In this case Gin provides a some lower level method called Handle. Please take a look at the following example:

package main

import (
 "net/http"

 "github.com/gin-gonic/gin"
)

func main() {
 router := gin.Default()
 router.GET("/hello", sayHello)
 router.Handle("LIST", "/get", getList)
 router.Run(":3000")
}

func sayHello(c *gin.Context) {
 c.JSON(http.StatusOK, gin.H{
  "message": "Hello!!",
 })
}

func getList(c *gin.Context) {
 // Gets the list of all categories
}

As you can see in the above example, instead of using the built-in methods, you can use the Handle method to use custom HTTP verbs. the Handle method takes three arguments instead of two, and the first argument is the method name in string. Using this you can have whatever method you prefer.

Hope it helps.

How to fix VSCode's Go extension high CPU usage

Writing Go code could be much easier if you use an IDE or text-editor plugin. Fortunately, there are some very good plugins for my text-editors of choice:

  • vim-go plugin for VIM which provides Golang language support
  • and Go extension for VSCode which provides the same functionality in Visual Studio Code.

The VSCode Go plugin however has an issue (or maybe misconfiguration): When using Go modules, the extension causes high CPU load!

The problem

To be able to solve a problem we must first identify exactly what the problem is. When writing code in any language, VSCode is constantly running process(es) in background to be able to suggest autocompletion, intellisense, auto imports, and etc.

By default, the VSCode’s Go plugin uses gocode tool to be able to provide autocompletion which is, as far as I understood, very slow and CPU intensive. This is an screenshot of macOS activity monitor when writing Go code in VSCode:

GoCode high CPU load

The solution

To be able to provide autocompletion, the Go team provided gopls.

gopls (pronounced: “go please”) is the official language server for the Go language.

I’m not sure why the extension is not using the Go’s default gopls tool for autocompletion. Maybe because the Go extension for VSCode was originally developed by Microsoft; but, recently it is maintained by the Go team at Google. As written in Go extension page:

This is the new home for the VS Code Go extension. We just migrated from Microsoft/vscode-go. Learn more about our move on the Go blog.

Maybe they change it in future.

The good news is that you can change the configuration! All we need to do is to tell VSCode to use the gopls language server instead of gocode tool. To make coding in Go more enjoyable, I suggest to turn formatOnSave and organizeImports on as well.

"go.useLanguageServer": true,
"go.buildOnSave": "off",
"[go]": {
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
        "source.organizeImports": true,
    },
    "editor.snippetSuggestions": "none",
},
"[go.mod]": {
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
        "source.organizeImports": true,
    },
},
"gopls": {
    "usePlaceholders": true
}

Note: In some cases, gopls tool may not be installed. If so, you can install it manually:

` go get -u golang.org/x/tools/gopls `

I saw a significant performance increase After switching to gopls and it became more enjoyable to write Go code. I hope you experience the same.

I am starting to like Golang

Lock down during COVID-19 pandemic continues and we have no choice but to stay home. Although we have missed lots things, it gives us the opportunity to learn and read more.

During the last four years, nearly all projects I worked on was written in Python. I like Python and it’s getting better every day. However, in the last 3 months or so, I had enough time to get familiar with Golang!

Learning curve

As a developer with near 15 years of working experiences, learning a new programming language shouldn’t be too hard; but, Golang was different. In the decade, every app I have developed, from C++ to Python and everything in between, was written with an object-oriented programming language. The most difficult challenge I faced when started developing my first practical application in Go was the lack of OOP principals. However, the more I used Go, the more I realized things can be done differently!

Here are some examples:

Exported Names

For example, although Golang does not have the encapsulation features such as private, public, protected or friend, it has something called exported name! When a function or field starts capital letter, it will be considered as an exported name which means it can be accessed from other packages.

package tools

// Private function. It can be accessed only inside tools package.
func sum(a, b int) int {
    return a + b
}

// Exported function. Anyone can access this function from other packages.
func Multiply(a, b int) int {
    return a * b
}

Struct methods

As an another example, because Go is not an OOP language, it doesn’t have classes; however, just like C, it has structs. Structs are types that are collection of fields. But unlike C, structs can have related methods! Please take a look the following example:

package example

type Person struct {
    ID uint
    FirstName string
    LastName string
    Age uint
}

// C like functions to return the full name
func GetPersonFullName(p *Person) string {
    return p.FirstName + " " + p.LastName
}

// Go struct methods
func (p *Person) GetFullName() string {
    return p.FirstName + " " + p.LastName
}

It’s still possible to write C-like code and it’s totally fine; but it could be much cleaner it you use the second method. Now let’s use the two functions we have written above:

package example

p := &Person{
    ID: 1,
    FirstName: "Mohammad Mahdi",
    LastName: "Ramezanpour",
    Age: 33,
}

// Call the first function
fullName := GetPersonFullName(p)

// Call the struct method
fullName := p.GetFullName()

Pointers

Go is a modern programming language and it has almost everything any modern programming language has. But unlike most of them, it has pointers! As you may know, pointers are game changers when it comes to high-performance software development. But they can be problematic as well!

In low-level languages such as C or C++, the developer is responsible for managing the memory and as all humans make mistakes, one can take a part of memory from the OS and forget to free it which could lead to memory leaks and app crashes. This is why some high-level programming languages such as Java and C# has something called garbage collector (GC). GC is responsible for taking care of memory allocations that are not in use anymore.

The great news is that Go has both pointers and GC!!! This simply let you have control over the memory but if you make a mistake, Go will take care of it.

Last words

As I’m getting deeper into Golang world, I’m getting more and more excited about the language. If you haven’t tried Go, you should definitely check it out. It’s the language to learn.