DEV Community

Cover image for Building microservices in Go with Fiber
Matt Angelosanto for LogRocket

Posted on • Edited on • Originally published at blog.logrocket.com

Building microservices in Go with Fiber

#go

Written by Subha Chanda✏️

Go, designed by Google engineers Robert Griesemer, Rob Pike, and Ken Thompson in 2007, is known for being fast and reliable, which is why it remains popular for web developers today. Go, combined with the power of microservices, helps build fast, efficient, and robust applications.

In this article, you’ll learn how to build microservices in Go using a package called Fiber, a Go framework that is inspired by the Node.js Express framework. It is built on top of the Fast HTTP package, known for being the fastest HTTP engine for Go.

What are microservices?

Microservices, or microservice architecture, is an architectural style that structures an application into a collection of services that are:

  • Maintainable
  • Testable
  • Loosely coupled
  • Independently deployable
  • Owned by a small team

A microservices architecture is a type of application architecture where the application is developed as a collection of services. It provides the framework to develop, deploy, and maintain microservices architecture diagrams and services independently (Google).

Microservice Architecture Wireframe The above diagram shows what a microservices architecture looks like. Notice that all the microservices are connected through an API gateway that communicates with the client.

Microservice architecture helps speed up the development process, and, because every service is minor, building the services can be done by small teams. It’s also easier to maintain and test the codes with a microservice.

Because all services are independent, it also offers improved fault isolation, so, if a single service fails, the whole system doesn't necessarily stop working.

What is Fiber?

Fiber is a web framework heavily inspired by Express. If you are coming from Node.js, Python, or Ruby, you'll find Fiber extremely easy to get started with. Go is fast, low on memory footprint, and highly performant, meaning it also makes the Fiber framework fast.

Fiber provides a robust routing mechanism and middleware is built-in for most tasks, and simplifies serving static assets or connecting to a database.

Fiber has thorough documentation, support, and a great community. Even though the primary use case for Fiber is to build an all-in-one web framework, it's also possible to create microservices with it.

How to use Fiber

Before moving directly to building a microservice using Fiber, let's look at a simple Hello World example. To get started, open a folder to save your file using your favorite text editor.

To install any dependency in this folder, initialize the directory using go mod. Run this command in your terminal: go mod init example.com/username/folder, where example.com can be any website where you store your code, the username is your username, and the folder is the folder name in which you want to keep the files.

Running this command will create a go.mod file in your working directory. This go.mod file tracks all the dependencies used in the project.

Now that the go.mod file is created, you are ready to install Fiber as a dependency. Run go get -u github.com/gofiber/fiber/v2 in your terminal to download the dependency.

Let's look at the Hello World example now to understand the basics of Fiber.

package main

import "github.com/gofiber/fiber/v2"

func main() {
    app := fiber.New()

    // Create a new endpoint
    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Hello World!")
    })

    // Start server on port 3000
    app.Listen(":3000")
}
Enter fullscreen mode Exit fullscreen mode

In the above example, the app := fiber.New() is initializing a new instance of Fiber. The app.Get method sets a Get request to the root route /, and a string is set up as a response in the root route sending the text Hello World!.

Finally, the app.Listen(":3000") is starting a server at port 3000. The above code will give the output below:

Hello World Output

Now that you have a basic understanding of how Fiber works, let's build a simple microservice using it.

Building microservices in Go using Fiber

The microservice we’ll build consists of two routes: the first route returns all the blog posts, and the second route returns the post depending on the ID.

/api/v1/post - returns all posts
/api/v1/:id - returns post that matches the ID
Enter fullscreen mode Exit fullscreen mode

Because this microservice is simple to build, we will not refactor the code into multiple files. Instead, the code will be a single main.js file. Also, we will not use a database in this use case.

In main.js, create a struct — which is a collection of fields — called Blog.

type Blog struct {
    Id    int    `json:"id"`
    Title string `json:"title"`
    Body  string `json:"body"`
}
Enter fullscreen mode Exit fullscreen mode

The above struct resembles a blog post. Each blog post will contain an ID, a title, and a body. json: defines the field names to show when it's rendered as JSON.

Next, create a variable called blogs of type Blog and define the values in this variable:

type blogPosts []Blog

var blogs = blogPosts{
    {Id: 1, Title: "Hello", Body: "Hello World!"},
    {Id: 2, Title: "Fiber", Body: "Fiber is fast!"},
    {Id: 3, Title: "Microservice", Body: "Microservice is awesome!"},
} 
Enter fullscreen mode Exit fullscreen mode

Defining routes in Go

Now, let’s define the routes.

func setupRoutes(app *fiber.App) {
    app.Get("/api/v1/post", GetPosts)
    app.Get("/api/v1/post/:id", GetPost)
}
Enter fullscreen mode Exit fullscreen mode

A function is created with the name setupRoutes. It takes an argument of fiber.App. Here, we are defining the routes. This function maps the endpoints with the functions passed as the second parameter.

app.Get("/api/v1/post", GetPosts) tells that upon a get request to route /api/v1/post, the GetPosts function will be called. And, on a get request to the route /api/v1/post/:id, where id is a variable, the GetPost function will be called.

Let's define the functions now. The GetPost function is a simple function that returns all the data from the blogs variable.

func GetPosts(c *fiber.Ctx) error {
    return c.JSON(blogs)
}
Enter fullscreen mode Exit fullscreen mode

fiber.Ctx returns a fasthttp.RequestCtx instance. It contains the incoming request and manages the outgoing response. The function returns the blogs variable by converting the variable to JSON.

Now we’ll build the GetPost function. Let’s look at the function first:

func GetPost(c *fiber.Ctx) error {
    id := c.Params("id")
    i, err := strconv.Atoi(id)
    if err != nil {
        return c.JSON(fiber.Map{"error": "Invalid ID"})
    }
    for _, s := range blogs {
        if s.Id == i {
            return c.JSON(s)
        }
    }
    return c.JSON(fiber.Map{"error": "Post not found"})
}
Enter fullscreen mode Exit fullscreen mode

The c.Params method gets the parameters passed in the route. The first step in this function is to store the parameter into a variable. The variable is defined as id and it stores the parameter id.

Because this is a simple example, we'll use a for loop to find the data. When working with a real database, you'll have methods to find the specific data.

By default, the Params method returns a string. You'll have to convert the string to an integer. Otherwise, it'll be impossible to compare an integer value with a string because the Id type of the Blog struct is of type int.

However, you can use the ParamsInt method to get an integer value from the route parameters using id, err := c.ParamsInt("id"). For this example, we’ll stick with the Params method.

The Atoi (“ASCII to integer”) method from the strconv package will be used to convert the value to an integer. This function returns two values, the converted result and the error.

The i and err variables store the converted value and the error, respectively. If the err variable is not nil, there is some error and the function will return a JSON value with the key-value pair of "error": "Invalid ID".

If the err is nil, the process jumps into the for loop. Inside the for loop, the ID value received from the parameter is compared with the IDs of the posts from the blogs variable. If the two values match, it'll return the particular struct value. In any other case, the function will return "error": "Post not found".

That was the last function needed for the routes. Now, we can look at the main function.

The main function in Fiber

Here's how the main function looks:

func main() {
    app := fiber.New()

    // Create a new endpoint
    app.Get("/", func(c *fiber.Ctx) error {
        return c.JSON(fiber.Map{"data": "Hello World!"})
    })

    setupRoutes(app)
    // Start server on port 3000
    app.Listen(":3000")
}
Enter fullscreen mode Exit fullscreen mode

First, Fiber is initialized with the fiber.New() method. Then, as a test route, the root route is set where it returns a map value of "data": "Hello World!". You've already seen the setupRoutes function above. The setupRoutes function holds the routes of our app.

The app instance is passed in this function to initialize the routes. Finally, a server is started at port 3000 using the app.Listen(":3000").

Now, we’re ready! If you run the main.go file from the terminal using go run main.go, it will start the server at your localhost port 3000. You can now test it using Postman or any API client you prefer.

Testing Fiber using Postman

If you visit endpoint localhost:3000/api/v1/post, you'll get all the values you defined in your blogs variable:

Blogs Variable Values

Visiting the route localhost:3000/api/v1/post/:id, where the id variable is an ID available in the blog posts, will return the specific post.

ID Variable

Conclusion

In this article, we covered the basics of microservice architecture and learned how to build microservices in Go using Fiber.

Fiber is fast and resembles the Node.js express framework, making it easier for a Node.js developer to transition to using Go. The complete code discussed in this article can be found in this repo.


LogRocket: Full visibility into your web apps

LogRocket signup

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

Try it for free.

Top comments (0)