How to Build REST API using Go Fiber and Gorm ORM
Tags: go, tutorial, webdev, programming
Published: 2022-01-01 13:03:53

## Overview

In the past I have written several articles about how we can interact with relational databases, however they were all for the JavaScript and TypeScript community. So this week I will share with you how we can create a simple API and perform a CRUD on a specific table in our database, this time in Go.

In this article, as in other articles I've written in the past in Golang, we'll use the [Fiber](https://gofiber.io/) framework, it's quite simple to use, has a good abstraction layer and contains everything we need to create our API. 

Regarding the interaction with the database, I decided to use an ORM to make the whole process simpler and more intuitive and for that reason I decided to use [Gorm](https://gorm.io/), which in my opinion is the most popular ORM in the Go universe and has a great range of features.

## Let's code

In today's example we are going to install only three dependencies, which are as follows:

```sh
go get github.com/gofiber/fiber/v2
go get gorm.io/gorm
go get gorm.io/driver/mysql
```

As you may have noticed, in this example I installed the MySQL driver because the database I have running in a docker container is MariaDB, however there are also drivers available for PostgreSQL and SQLite.

Now let's start by defining our Entity, which will have a total of four properties:

- `Name` - the name of the dog
- `Age` - the age of our four legged friend
- `Breed` - our friend's race
- `IsGoodBoy` - whether our friend has been a good boy or not

Similar to the following:

```go
// @/entities/dog.go
package entities

import "gorm.io/gorm"

type Dog struct {
	gorm.Model
	Name      string `json:"name"`
	Breed     string `json:"breed"`
	Age       int    `json:"age"`
	IsGoodBoy bool   `json:"isGoodBoy" gorm:"default:true"`
}
```

Now we can proceed to the configuration of the connection with the database. In this case I like to create a function called `Connect()` that will be responsible for initializing the connection, besides that it will also be responsible for performing the migrations in our database. This way:

```go
// @/config/database.go
package config

import (
	"github.com/FranciscoMendes10866/gorm/entities"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var Database *gorm.DB
var DATABASE_URI string = "root:root@tcp(localhost:3306)/gorm?charset=utf8mb4&parseTime=True&loc=Local"

func Connect() error {
	var err error

	Database, err = gorm.Open(mysql.Open(DATABASE_URI), &gorm.Config{
		SkipDefaultTransaction: true,
		PrepareStmt:            true,
	})

	if err != nil {
		panic(err)
	}

	Database.AutoMigrate(&entities.Dog{})

	return nil
}
```

Now that we have our Entity defined and the connection to our database configured, we can start working on our handlers. Each of our handlers will correspond to a route from our API, so each one will be responsible for executing only one operation. First let's get all the records we have in our database table.

```go
// @/handlers/dog.go
package handlers

import (
	"github.com/FranciscoMendes10866/gorm/config"
	"github.com/FranciscoMendes10866/gorm/entities"
	"github.com/gofiber/fiber/v2"
)

func GetDogs(c *fiber.Ctx) error {
	var dogs []entities.Dog

	config.Database.Find(&dogs)
	return c.Status(200).JSON(dogs)
}

// ...
```

Now let's get just one record according to the `id` parameter that will be sent in the request parameters.

```go
// @/handlers/dog.go
package handlers

// ...

func GetDog(c *fiber.Ctx) error {
	id := c.Params("id")
	var dog entities.Dog

	result := config.Database.Find(&dog, id)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(&dog)
}

// ...
```

Now that we can get all the records and also just one record. We lack the functionality to insert a new one in the database table.

```go
// @/handlers/dog.go
package handlers

// ...

func AddDog(c *fiber.Ctx) error {
	dog := new(entities.Dog)

	if err := c.BodyParser(dog); err != nil {
		return c.Status(503).SendString(err.Error())
	}

	config.Database.Create(&dog)
	return c.Status(201).JSON(dog)
}

// ...
```

We still need to add the functionality to update an existing record in our database. And similar to what we've already implemented, let's use the `id` parameter to update the specific record.

```go
// @/handlers/dog.go
package handlers

// ...

func UpdateDog(c *fiber.Ctx) error {
	dog := new(entities.Dog)
	id := c.Params("id")

	if err := c.BodyParser(dog); err != nil {
		return c.Status(503).SendString(err.Error())
	}

	config.Database.Where("id = ?", id).Updates(&dog)
	return c.Status(200).JSON(dog)
}

// ...
```

Last but not least, we need to delete a specific record, again we will use the id parameter to remove the specific record from our database.

```go
// @/handlers/dog.go
package handlers

// ...

func RemoveDog(c *fiber.Ctx) error {
	id := c.Params("id")
	var dog entities.Dog

	result := config.Database.Delete(&dog, id)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.SendStatus(200)
}

// ...
```

Now we just need to create our main file that will be responsible for initializing the connection to the database and where our API routes will be defined and a handler will be associated to each one of them.

```go
// @/main.go
package main

import (
	"log"

	"github.com/FranciscoMendes10866/gorm/config"
	"github.com/FranciscoMendes10866/gorm/handlers"
	"github.com/gofiber/fiber/v2"
)

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

	config.Connect()

	app.Get("/dogs", handlers.GetDogs)
	app.Get("/dogs/:id", handlers.GetDog)
	app.Post("/dogs", handlers.AddDog)
	app.Put("/dogs/:id", handlers.UpdateDog)
	app.Delete("/dogs/:id", handlers.RemoveDog)

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

## Conclusion

As always, I hope you found it interesting. If you noticed any errors in this article, please mention them in the comments. 🧑🏻‍💻

Hope you have a great day! 🚨