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.

Switching from Evernote

For the last 8 years or so, I have been using Evernote to take my notes and capture my ideas. I call myself a loyal customer to Evernote because I didn’t move to other alternatives even after they have restricted the number of concurrent devices to two! I waited for about 5 years to see some good new features and to be honest, the only good feature they have added since the first day I started using it was dark mode. I hope I could see some other features such as right-to-left languages support or better hierarchy category structure but they haven’t add any of these until now. So I decided to switch!

Options

I started investigating about other options I have to switch to. In fact, there are dozens of note-taking applications out there but in my opinion, only a few of them are deserved to be called an alternative to Evernote! Here is my shortlist:

  • Google Keep
  • Microsoft OneNote
  • Apple Notes

I tried Google Keep but the fact that it doesn’t have any desktop application really hurts me. It’s also more like sticky notes rather than “real notes”. Also, I have tried OneNote before. OneNote is really great option but I think it’s more intended to be used by students because it’s really similar to university textbooks. What I need in particular is a simple text area (similar to Evernote) where I can just type! Moreover, I want the support for RTL languages because I write my daily journal mostly in Persian.

Apple Notes

I know most people may blame me for choosing Apple Notes over all other alternatives; but, the fact is that it covers most of my needs! Here are some of my key point:

  • I own a MacBook and an iPhone; and as expected, Apple Notes works seamlessly on my devices.
  • It syncs automatically via iCloud and it can even be accessed via a web browser if I don’t carry any of my devices (which is rare but possible).
  • Apple Notes does support right-to-left languages (which Evernote doesn’t).
  • Just like Evernote, Apple Notes supports search in photos! If you scan a document for example, you can simply search through it.
  • It’s completely free! Unlike Evernote and most other alternatives, you can save notes up to your iCloud storage capacity (5GB by default)!

I believe you don’t use 80% of features apps offer (especially productivity apps) and I believe simplicity is good. Apple Notes is simply a note-taking application which offers only essentials and it’s enough.