Create RESTFul CRUD API using Golang Fiber [Tutorial]


GO

Reviewer: Deepak Prasad

Getting started with Golang Fiber

Go Fiber is one of the few frameworks in Go that you can use to build APIs with minimal effort. Go Fiber was inspired by Node JS Express framework and any one coming from the Nodejs world will see the similarities between these two. If you come from other languages like Python , Ruby or Go , there is nothing to worry about because Go Fiber is easy to use and set up as you will see in this article.

Fiber is built on top of Fasthttp which is the fastest HTTP engine in Go. It is designed to make things easy for the developer hence fast software development with zero memory allocation and performance. As you would expect, Fiber comes with very many capabilities that are required in API development world such as:

  1. HTTP routing
  2. HTTP status codes
  3. Send text messages
  4. Send files
  5. Send JSON
  6. Static file handling
  7. HTML template Engine
  8. Query parameter handling

To learn more about the above list, read golang fiber. This article will focus on how to build a simple API that performs the Create, Read, Update and Delete operations CRUD. We will use Fiber to handle HTTP requests and we will use data types like maps and structs to store our data temporarily. In this article, our data will be persisted in memory and not in any database. We will build an Article API that allows clients to create, read , update and delete articles.

 

Prerequisite

  1. Go version 1.1.4 and higher
  2. Basic Go knowledge like Maps, Structs, Function etc.
  3. Postman installation and familiarity using Postman

 

Application structure

The main focus of this article is on how to build a simple RESTful API using Go Fiber, therefore we will keep the application structure as simple as possible. The image below  demonstrates how our application will look like.

Create RESTFul CRUD API using Golang Fiber [Tutorial]

 

 

 

 

 

 

 

Follow the below steps to create the above application structure.

Create root directory and move into the root directory

$ mkdir go-fiber-api && cd go-fiber-api

Create database package and api package

$ mkdir database api

Create the main entry point

$touch main.go

To get up and running, we are going to have a taste of Go Fiber. We are going to create a Fiber application, create a home route and make the Fiber application listen to port 5000. We can set the ball rolling by initializing a go module and installing the Fiber package. The next steps will initialize a go module and install Fiber.

Initialize a go module. Ensure you are at the root folder same with the main.go file.

$ go mod init example.com/go-fiber-api

Install Fiber

$ go get github.com/gofiber/fiber/v2

 

GO Fiber Server setup

In this section,we are going to set up the fiber server so that we can test it before we can start building the API. In the main.go file, add the below code.

main.go

package main
 
import "github.com/gofiber/fiber/v2"
 
func main() {
   app := fiber.New()
 
   app.Get("/", func(c *fiber.Ctx) error {
       return c.SendString("Welcome to Go Fiber API")
   })
 
   app.Listen(":5000")
}

In the above code sample,we import the installed Fiber package into the main package. The main function is where all the code starts running from. We initialize a fiber app using the line app := fiber.New() command. The app instance has CRUD method that we can access and in the above example, we use  the Get method that routes traffic into the server. This route exposes the home route (“/”). This means that when a client hits http://127.0.0.1:3000 in the browser, this route will be activated and if there is no error, we will return a string to the client. If you add http://127.0.0.1:3000 address on your browser URL , you will get a string response.

Running Fiber API

In the terminal, run the server by issuing this command.

$ go run main.go

┌───────────────────────────────────────────────────┐
│                   Fiber v2.39.0                   │
│               http://127.0.0.1:3000               │
│       (bound on host 0.0.0.0 and port 3000)       │
│                                                   │
│ Handlers ............. 2  Processes ........... 1 │
│ Prefork ....... Disabled  PID .............. 8483 │
└───────────────────────────────────────────────────┘

 

Setting up a data store (CRUD Operation)

Our example is a very simple one, and we are not going to complicate things. In the database package, we are going to add an Article model that is made up of a struct. This struct will contain the properties of an article such as ID, title, author , rating and description. Our Go Fiber API will import the model and manipulate it as needed. In the database package add a model.go file and add the below code.

Add models.go file

$ cd database && touch model.go

database/model.go

package database
 
type Article struct {
   ID          string `json:"id"`
   Title       string `json:"title"`
   Description string `json:"description"`
   Rate        int    `json:"rate"`
}

The above example is a simple article that we will use in our API. An article must have the above attributes. Each attribute has been annotated to json so that data can be more readable while consuming it.

Next we are going to add all the CRUD operations in the API package.

Move to the root folder and move to the api package.

$ cd .. && cd api

Create fiber.go file

$ touch fiber.go

At the beginning of the fiber.go file, import the required code from the database package, fiber and UUID as shown below. We also initialize an articles map that has a string key and article as the value. We are using the map data structure because it is much faster and easy to add, get , update and delete items from a map.

 

Create Operation

package api
 
import (
   "example.com/go-fiber-api/database"
   "github.com/gofiber/fiber/v2"
   "github.com/google/uuid"
)
 
var (
   articles = map[string]database.Article{}
)
func createArticle(c *fiber.Ctx) error {
   article := new(database.Article)
 
   err := c.BodyParser(&article)
 
   if err != nil {
       return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
           "errors": err.Error(),
       })
 
   }
 
   article.ID = uuid.New().String()
  
   articles[article.ID] = *article
 
   c.Status(200).JSON(&fiber.Map{
       "article": article,
   })
 
   return nil
}

In this section, the goal is to receive data from the client and add the data into the articles map. We use the createArticle() function that takes as an argument a fiber context and returns an error if any. We initialize a new article using article := new(database.Article). This command returns an article variable as a pointer. Fiber uses pointers instead of passing by value or making copies of a variable for better memory management.The fiber context comes with BodyParser() method that marshals the  incoming data from client and ensures that it matches with the Article struct . If the data do not match, an error will be returned. The status code for each returned response can be added by passing the Status() method and passing it the status code number for example, 404 for item not found or 200 for successful request.

If there was no error, we add an uuid to the article ID key, using article.ID=uuid.New().String(). After assigning the ID, we add the article in the articles map, and return to the caller, all the available articles.

 

Read Operation

func readArticle(c *fiber.Ctx) error {
   id := c.Params("id")
 
   if article, ok := articles[id]; ok {
       c.Status(200).JSON(&fiber.Map{
           "article": article,
       })
   } else {
       c.Status(404).JSON(&fiber.Map{
           "error": "article not found",
       })
   }
   return nil
}

Using the Fiber context, we get the id of the articles to read from our articles map using the command id := c.Params(“id”) .Please note the string “id” is part of the URL parameters e.g http://0.0.0.0:3000/api/v1/articles/1 where 1 is the ID of the article to read data. We then use the ID to check if it exists in the articles map. If an article with the id is found , it is returned back to the caller with status code 200, else an error message will be returned with a 404 status code.

 

Read All Articles

func readArticles(c *fiber.Ctx) error {
   c.Status(200).JSON(&fiber.Map{
       "articles": articles,
   })
   return nil
}

This is the simplest and straightforward function. It returns all the articles present to the client with status code 200.

 

Update Operation

func updateArticle(c *fiber.Ctx) error {
   updateArticle := new(database.Article)
 
   err := c.BodyParser(updateArticle)
 
   if err != nil {
       c.Status(500).JSON(&fiber.Map{
           "error": err.Error(),
       })
       return err
   }
   id := c.Params("id")
   if article, ok := articles[id]; ok {
       article.Title = updateArticle.Title
       article.Description = updateArticle.Description
       article.Rate = updateArticle.Rate
       articles[id] = article
       c.Status(200).JSON(&fiber.Map{
           "article": article,
       })
   } else {
       c.Status(404).JSON(&fiber.Map{
           "error": "article not found",
       })
 
   }
   return nil
}

The update function receives updated articles from the client and updates the existing articles in our articles map. We initialize an empty article using updateArticle := new(database.Article) command. This updateArticle variable is parsed by the context using the command err := c.BodyParser(updateArticle). If this command is successful , we proceed to updating the article, else we return an error to the client with status code 500.

We then get the id of the item to update using the command id := c.Params(“id”). This id variable is used to get the article to update from the articles map. We check if the article exists using the id , and update it if the article with the given id exists. After a successful update , we return the updated article to the client with status code 200.

 

Delete Operation

func deleteArticle(c *fiber.Ctx) error {
   id := c.Params("id")
 
   if _, ok := articles[id]; ok {
       delete(articles, id)
       c.Status(200).JSON(&fiber.Map{
           "message": "article deleted successfully",
       })
   } else {
       c.Status(404).JSON(&fiber.Map{
           "error": "article not found",
       })
   }
 
   return nil
}

The deleteArticle function uses id to delete an article from the articles map if it exists.We first get the id of the article using the command id := c.Params(“id”) and check if the id exists in the articles map using the statement _, ok := articles[id]. If the article is found we use the delete() function from the standard library to delete the article with the given id from the articles map using the statement delete(articles, id). After a successful delete operation, we return to the client a message confirming article deletion with status code 200. If the article does not exist in the map, we return an error message to the client with status code 404.

 

Route handler

func SetupRoute() *fiber.App {
   app := *fiber.New()
   app.Post("/api/v1/articles", createArticle)
   app.Get("/api/v1/articles/:id", readArticle)
   app.Get("/api/v1/articles/", readArticles)
   app.Put("/api/v1/articles/:id", updateArticle)
   app.Delete("/api/v1/articles/:id", deleteArticle)
   return &app
}

The SetupRoute() function is responsible for creating a fiber app and matching incoming requests to their respective handle functions. This is where all the magic happens, because HTTP methods get mapped to their respective handler functions. For example, app.Post(“/api/v1/articles”) is responsible for routing all POST requests to the createArticle handler function. The SetupRoute() function starts with capital letter S meaning it's an exported function and can be accessed from other packages. We will use it in the main function. The SetupRoute() function returns a fiber app to the caller.

main.go

package main
 
import (
   "example.com/go-fiber-api/api"
   "github.com/gofiber/fiber/v2"
)
 
func main() {
   app := api.SetupRoute()
 
   app.Get("/", func(c *fiber.Ctx) error {
       return c.SendString("Welcome to Go Fiber API")
   })
 
   app.Listen(":3000")
}

The main function is responsible for booting up the application and calling the necessary functions such as the SetupRoute() function. We import the fiber package together with the api package. The fiber package gives us access to the *fiber.Ctx while the api package gives us access to the SetupRoute() function.

To initialize the application, we use app:= SetupRoute() statement. The returned app function exposes the CRUD routes defined in the api package .

In the next line , we add a home route that returns a "Welcome to Go Fiber API" string to the client for requests to the “/” route .

To spin up the server, we use the app.Listen(“:3000”) statement. This means that the server will be accessed on port 3000 which translates to http://0.0.0.0:3000  or http://127.0.0.1:3000  on your local machine.

 

Running the application

Before running the application, we need to ensure that all of our dependencies have been installed. The go mod tidy ensures that all dependencies  have been installed. In the terminal in your root folder, issue this command.

$ go mod tidy

To run the application issue the below command.

$ go run main.go
 
┌───────────────────────────────────────────────────┐
│                   Fiber v2.39.0                   │
│               http://127.0.0.1:3000               │
│       (bound on host 0.0.0.0 and port 3000)       │
│                                                   │
│ Handlers ............. 9  Processes ........... 1 │
│ Prefork ....... Disabled  PID ............. 35437 │
└───────────────────────────────────────────────────┘

 

Performing CRUD operations using Postman

In this section, we are going to use the famous API testing application called Postman. Please ensure you have it installed in your machine. The first operation that we are going to perform is the POST request.

 

Create Articles (POST)

Create RESTFul CRUD API using Golang Fiber [Tutorial]

To POST a new article using Postman, ensure that you use the POST HTTP method and add data for the new article, with the Body tab and press the send button. Feel free to perform multiple POST operations so that you can be able to view them in the Read All Articles section

 

Read Article

Create RESTFul CRUD API using Golang Fiber [Tutorial]

To read a single article, ensure that the GET , use the GET HTTP method in Postman and add the id of the article in the URL bar i.e http://0.0.0.0:3000/api/v1/articles/0cd9385e-c982-40d9-9ad0-cefed55a8eb5 and press the Send blue button.

 

Read All Articles

Create RESTFul CRUD API using Golang Fiber [Tutorial]

To read all the articles, use the GET HTTP method in Postman and add http://0.0.0.0:3000/api/v1/articles in the URL bar to get all the articles.

 

Update Article

Create RESTFul CRUD API using Golang Fiber [Tutorial]

To update an article , use the PUT HTTP method in Postman, and use the id of the articles to update in the URL bar. In the body section, add the content of the updated article ensuring that all fields are valid and press the Send button. At the bottom part an updated article will be returned. In the above example, we change the author name from Mary Doe to John Doe

 

Delete Article

Create RESTFul CRUD API using Golang Fiber [Tutorial]

To delete an article, use the DELETE HTTP method in Postman, and add the id of the article to delete in the URL i.e http://0.0.0.0:3000/api/v1/articles/0cd9385e-c982-40d9-9ad0-cefed55a8eb5 and press Send button. A string will be returned back indicating that the article has been deleted if the operation is successful.

 

Summary

Fiber is an easy to use API framework for Go. It was inspired by Express js  in the JavaScript environment. It has minimal memory footprint and it is fast and performant. In this article we learn about the CRUD operations and use Fiber for routing all our HTTP requests.

 

References

https://docs.gofiber.io
https://dev.to/koddr/go-fiber-by-examples-how-can-the-fiber-web-framework-be-useful-487a

 

Antony Shikubu

Antony Shikubu

He is highly skilled software developer with expertise in Python, Golang, and AWS cloud services. Skilled in building scalable solutions, he specializes in Django, Flask, Pandas, and NumPy for web apps and data processing, ensuring robust and maintainable code for diverse projects. You can reach out to him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment