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:
- HTTP routing
- HTTP status codes
- Send text messages
- Send files
- Send JSON
- Static file handling
- HTML template Engine
- 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
- Go version 1.1.4 and higher
- Basic Go knowledge like Maps, Structs, Function etc.
- 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.
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)
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
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
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
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
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