Building basic CRUD operations in Go with Fiber
Tags: go, beginners, tutorial
Published: 2021-09-04 03:19:05

---
title: Building basic CRUD operations in Go with Fiber
published: true
date: 
tags: go, beginners, tutorial
canonical_url: https://eternaldev.com/blog/building-basic-crud-operations-in-go-with-fiber
---

## Fiber Basics

Fiber is a Go package that helps in building API for Web Development. It is inspired by Express framework from Node.js and built on top of [https://github.com/valyala/fasthttp](https://github.com/valyala/fasthttp). If you have prior experience with building API with node.js, it will be easier to start with Fiber in Go.

Don't worry if this is your first time building an API server, We will go into detail about how to set up the API with multiple endpoints and working with a database to building a simple Bookmarking API.

Originally published at https://eternaldev.com/blog/building-basic-crud-operations-in-go-with-fiber

## What are we building?

We are browsing the depths of the internet all day and more often than not, we will come up with links that are interesting. You might be familiar with the browser bookmarking feature which will add the link to the browser and we will replicate that feature in our application.

[![FiberAPI_building.jpg](https://eternaldev.com/static/d22f0da47854fb7ed840c891a1f1036d/f9218/fiberapi_building.jpg "FiberAPI\_building.jpg")](/static/d22f0da47854fb7ed840c891a1f1036d/f9218/fiberapi_building.jpg)

We will have a simple data model for this app.

Name - User-defined name for the bookmark

URL - HTTP link of the website

```go
type Bookmark struct {
	Name string
	Url string
}
```

## Creating the first endpoint

Let's get started with setting up our Go application with `go mod` command. Create a new folder and initialize the go project.

```go
mkdir bookmark-api-fiber
cd bookmark-api-fiber
go mod init <repo_name>
```

### Adding the Fiber package

Install the Fiber package using the `go get` command

```go
go get -u github.com/gofiber/fiber/v2
```

We can set up our server which will wait and listen for requests.

```go
package main

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

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

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

    app.Listen(":3000")
}
```

Let's breakdown the above syntax to create a new API server.

```go
app := fiber.New() // Create a new instance of Fiber

app.Get("/", func(c *fiber.Ctx) error {
    return c.SendString("Hello, World 👋!")
})
```

Creating a GET endpoint for your application. This is a pattern from REST that will allow us to get some information from the server. If you are a beginner with REST, you can follow this link

[https://www.smashingmagazine.com/2018/01/understanding-using-rest-api/](https://www.smashingmagazine.com/2018/01/understanding-using-rest-api/)

GET endpoints usually return some information needed by the client. In our example, we are returning the string "Hello, World 👋!"

```go
 app.Listen(":3000")
```

Fiber server will need to run on a particular port when you start the application. You can define the port number and so this app will run in localhost:3000

### Run the Fiber app

```go
go run main.go

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

Yay! we have started our server and this process will wait for any request which comes into the url

## Creating a new package for bookmark logic

Create a new folder called `bookmark` and add all the logic of the bookmark inside that folder. This helps in separating the API routing logic and business logic and keeping the app nice and tidy.

```go
	package bookmark
	
	import "github.com/gofiber/fiber/v2"
	
	func GetAllBookmarks(c *fiber.Ctx) error {
		return c.SendString("All Bookmarks")
	}
	
	func SaveBookmark(c *fiber.Ctx) error {
		return c.SendString("Bookmark Saved!")
	}
```

Update the main go file to import the bookmark package and use them in the routes

```go
package main

import (
	"bookmark-api-fiber/bookmark"
	"github.com/gofiber/fiber/v2"
)

func status(c *fiber.Ctx) error {
	return c.SendString("Server is running! Send your request")
}

func setupRoutes(app *fiber.App) {

	app.Get("/", status)

	app.Get("/api/bookmark", bookmark.GetAllBookmarks)
	app.Post("/api/bookmark", bookmark.SaveBookmark)
}

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

	setupRoutes(app)
	app.Listen(":3000")
}
```

Main function is split into multiple methods as well. Routing logic is made into a separate function called `setupRoutes` which takes the pointer to the Fiber app.

Default `/` route is set to return a status string. This can help to validate if your app is running properly.

### Explanation of other routes

It is a convention when building API to prefix all the routes with `/api` which will clearly mark them as API. You can define all the REST endpoints for a particular resource using the resource name after that.

Our resource name is `bookmark`

We can define our REST verbs like below

1. /api/bookmark - GET endpoint for list of bookmarks
2. /api/bookmark - POST endpoint to save a new bookmark

## Database setup

Let's follow a similar pattern like bookmark package and create a new folder called `database` and create a file called `database.go`

### Sqlite3

We will make use of sqlite3 for the database. It has a simple interface for saving and loading data and it gets stored in .db file in the project. This is not the best solution for production-ready apps but this will do for our demo to store and retrieve data.

> Note from sqlite3 package: this is a CGO enabled package you are required to set the environment variable CGO\_ENABLED=1 and have a gcc compile present within your path.

### GORM - ORM for Go

We will use an ORM ([Object-Relational-Mapping](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping)) to make our interaction with the database easier. If you opt for directly working with the database, you need to write database queries to perform operations on the database. ORM makes it easier by taking care of converting our requests into queries and giving a simple API for us to read, write data to the database.

More info on what is ORM - [https://blog.bitsrc.io/what-is-an-orm-and-why-you-should-use-it-b2b6f75f5e2a](https://blog.bitsrc.io/what-is-an-orm-and-why-you-should-use-it-b2b6f75f5e2a)

Installing sqlite3 and Gorm

```go
go get -u github.com/mattn/go-sqlite3
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
```

### Initialize the database with the model

We will use a table to store our data. In Sqlite3, we will need to define columns with types in the database. This can be made simple using ORM when we define the model we want to store. Gorm takes care of the heavy lifting of creating a table with the right columns.

We also get a few extra bookkeeping columns when creating the model with Gorm such as "ID, CreatedAt, UpdatedAt, DeletedAt"

```go
type Bookmark struct {
	gorm.Model
	Name string `json:"name"`
	Url string `json:"url"`
}
```

Model is defined as a `struct` with JSON names that will be used when converting the model into JSON and sending it back to the client.

```go
func InitDatabase() error {
	db, err := gorm.Open(sqlite.Open("bookmark.db"), &gorm.Config{})
	if err != nil {
		return err
	}

	db.AutoMigrate(&Bookmark{})

	return nil
}
```

`InitDatabase` function is defined which will try to establish a connection with the database. If the file is not present, it will create a new file with the name "bookmark.db"

AutoMigrate call helps in creating the table if it is not already present. Database migration are usually things that change the structure of the database over time and this helps in making sure that the database structure is properly migrated to the latest version.

Update the main.go file to initialize database

```go
func main() {
	app := fiber.New()
	dbErr := database.InitDatabase()

	if dbErr != nil {
		panic(dbErr)
	}

	setupRoutes(app)
	app.Listen(":3000")
}
```

## Post Request to add a bookmark

Let's start by sending a POST request to the server to create a new bookmark to store in the database. Using Gorm we can simplify the process by calling the Create method on the database and passing in the necessary data needed.

Update the code in the `bookmark.go` file to send the request to the database

```go
func SaveBookmark(c *fiber.Ctx) error {
	newBookmark := new(database.Bookmark)

	err := c.BodyParser(newBookmark)
	if err != nil {
		c.Status(400).JSON(&fiber.Map{
			"success": false,
			"message": err,
			"data": nil,
		})
		return err
	}

	result, err := database.CreateBookmark(newBookmark.Name, newBookmark.Url)
	if err != nil {
		c.Status(400).JSON(&fiber.Map{
			"success": false,
			"message": err,
			"data": nil,
		})
		return err
	}

	c.Status(200).JSON(&fiber.Map{
		"success": true,
		"message": "",
		"data": result,
	})
	return nil
}
```

It is a good practice to return a predefined structure as a response to the API request along with Status code and message.

We can use the `BodyParser` function to convert the POST request data into our model format. We are sending that data to the database to create a new record

```go
func CreateBookmark(name string, url string) (Bookmark, error) {
	var newBookmark = Bookmark{Name: name, Url: url}

	db, err := gorm.Open(sqlite.Open("bookmark.db"), &gorm.Config{})
	if err != nil {
		return newBookmark, err
	}
	db.Create(&Bookmark{Name: name, Url: url})

	return newBookmark, nil
}
```

[![POST Request to send bookmark data](https://eternaldev.com/static/3891119c8ff8665a48661c0e3841ce2e/b6e50/request1.png "POST Request to send bookmark data")](/static/3891119c8ff8665a48661c0e3841ce2e/b6e50/request1.png)

I am using a VS Code extension "Thunder Client" to send the POST request but you can use any tool which you are comfortable with and send the JSON to the POST request

```json
{
    "name": "Go blog website",
    "url": "https://eternaldev.com"
}
```

A little bit of self-promotion there to save this site as your bookmark. This is the gist of thing to send a POST request and save the data to the database.

## Getting the bookmark

Update the `bookmark.go` file for the `GetAllBookmarks` function as well.

```go
func GetAllBookmarks(c *fiber.Ctx) error {
	result, err := database.GetAllBookmarks()
	if err != nil {
		return c.Status(500).JSON(&fiber.Map{
			"success": false,
			"message": err,
			"data": nil,
		})
	}

	return c.Status(200).JSON(&fiber.Map{
		"success": true,
		"message": "",
		"data": result,
	})
}
```

In our use case, the GET request does not need any data to be sent. We just want the list of all the bookmarks which is saved. So we can call the database to return all the bookmark data. Check for any error and then send the Status Code 500 if there is an error from the database call.

If there is no error we can send the data in a similar format and setting the success to true.

```go
func GetAllBookmarks() ([]Bookmark, error) {
	var bookmarks []Bookmark

	db, err := gorm.Open(sqlite.Open("bookmark.db"), &gorm.Config{})
	if err != nil {
		return bookmarks, err
	}

	db.Find(&bookmarks)

	return bookmarks, nil
}
```

Update the database file to return a list of bookmarks from the database. Find function can be used to get the list of items. You just have to pass the variable to store the data.

[![GET Request to get bookmark data](https://eternaldev.com/static/84b9f0f58d90d9ede1c0b8cafd57de0c/71ba4/request2.png "GET Request to get bookmark data")](/static/84b9f0f58d90d9ede1c0b8cafd57de0c/71ba4/request2.png)

Output of GET Request

```json
{
  "data": [
    {
      "ID": 1,
      "CreatedAt": "2021-09-03T19:29:56.5726629+05:30",
      "UpdatedAt": "2021-09-03T19:29:56.5726629+05:30",
      "DeletedAt": null,
      "name": "Go blog website",
      "url": "https://eternaldev.com"
    },
    {
      "ID": 2,
      "CreatedAt": "2021-09-03T19:30:27.4942284+05:30",
      "UpdatedAt": "2021-09-03T19:30:27.4942284+05:30",
      "DeletedAt": null,
      "name": "Go official website",
      "url": "https://golang.org/"
    }
  ],
  "message": "",
  "success": true
}
```

## Source code

[https://github.com/eternaldevgames/bookmark-api-fiber](https://github.com/eternaldevgames/bookmark-api-fiber)

## Summary

Fiber can help you in building API using golang and there are multiple ways to improve the above code. You can add updating and deleting the bookmark functionality. If you like this article, let us know on the Discord server and we can make it into a detailed series covering Fiber in Go

Stay tuned by subscribing to our mailing list and joining our Discord community

[Discord](https://discord.gg/AUjrcK6eep)