Simple API in Go with Fiber

According to the StackOverflow Developer Survey and the TIOBE index, Go (or Golang) has gained more traction in recent years, especially among backend developers and DevOps teams working on infrastructure automation. That’s reason enough to write a simple tutorial to introduce you to Go.

It’s worth learning it, so in this article, I wanna show you a brief guide on how to develop a scalable but simple CRUD API in Go using Fiber and GORM. For the sake of simplicity, we won’t use Docker.

Fiber is an Express-inspired web framework built on top of Fasthttp, the fastest HTTP engine for Go. Designed to ease things up for fast development with zero memory allocation and performance in mind. So if you come from a NodeJS background, Fibe might be a good fit.

The project will be very classic. We are going to build a simple Book CRUD-based API. So we are going to have different endpoints for create, read, update, and delete.

You need to have a basic understanding of Go. I will choose Visual Studio Code as my code editor. You can use whatever you prefer. But keep in mind, that you’ll see the command code . once in this article. This is a VSCode (Visual Studio Code) specific command which opens the current directory in VSCode.

You also need to install these:

  • Install Go on your local machine
  • Install Postgres on your local machine

Any recent version of both is okay. However, my Go version is 1.18 and PostgreSQL is version 14.

First, we need to create a Postgres database. I know, everybody handles that differently, some people use a GUI, but we are going to use our terminal. Again, you need to have Postgres installed on your machine. If you have Postgres installed, the following four commands will run on Linux, Mac, and Windows machines.

$ psql postgres
$ CREATE DATABASE go_fiber_api;
$ l
$ q
  • psql postgres open psql CLI with user postgres
  • CREATE DATABASE go_fiber_api; creating the database we need
  • l list all databases
  • q CLI exit

My terminal would look like this after we executed all four commands successfully. As we can see, the database go_fiber_api was created.

First of all, we are going to initiate our project and install the modules we need.

Watch out: Replace YOUR_USERNAME with your Github username.

$ mkdir go-fiber-api
$ cd go-fiber-api
$ code .
$ go mod init github.com/YOUR_USERNAME/go-fiber-api

Now let’s install Fiber, GORM, and Viper. We use Viper to manage our Environment Variables.

$ go get github.com/spf13/viper
$ go get github.com/gofiber/fiber/v2
$ go get gorm.io/gorm
$ go get gorm.io/driver/postgres

Let’s continue with the final project structure.

$ mkdir -p cmd pkg/books pkg/common/db pkg/common/envs pkg/common/models

Additionally, let’s add some files.

$ touch Makefile cmd/main.go pkg/books/add_book.go pkg/books/controller.go pkg/books/delete_book.go pkg/books/get_book.go pkg/books/get_books.go pkg/books/update_book.go pkg/common/db/db.go pkg/common/envs/.env pkg/common/models/book.go

So, after creating our project, the file structure should look like this:

Now, it’s time to code.

First, we need to add some environment variables where we store the application port we are going to listen on and we URL to the database. Keep in mind, to replace DB_USER, DB_PASSWORD, DB_HOSTand DB_PORT with your database data.

Let’s add code to pkg/common/envs/.env

For instance, how it would look on my local machine:

Let’s add code to pkg/common/config/config.go

Here, we are going to create the Book model/entity. gorm.Model will add properties such as ID, CreatedAt, UpdatedAt and DeletedAt for us.

In addition, we add 3 string properties. The json tag at the end gives GORM the information of each column’s names in our Postgres database.

Let’s add code to pkg/common/models/book.go

The book model is done. Now, we configure GORM and auto migrate the model we just created. This AutoMigrate function will create the books table for us as soon as we run this application.

Let’s add code to pkg/common/db/db.go

This is our bootstrap file. We are going to do a lot here.

  • Initializing Viper to handle our environment variables
  • Initializing the database based on GORM
  • Adding a simple “/” route
  • Starting the application

We’re going to change this file later once again.

Let’s add code to cmd/main.go

Now, let’s test the current version of our project. Usually, the application will run in debug mode, so we will get some warnings, just ignore them.

$ go run cmd/main

Output inside the console. The very last line is important.

Let’s visit http://localhost:3000

Open Application in Browser

Great. We can see our application’s port. This means everything works as expected.

Great, everything works. We’re going to replace this output, so don’t worry. Now, let’s add some handlers for our Book API.

Controller

The book handlers/routes will be based on so-called pointer receivers, for that, we define its struct. This struct will receive the database information later, so whenever we call a book handler/route, we will have access to GORM. We’re going to change this file once later again.

Let’s add code to pkg/books/controller.go

Add Book Handler

So this file is very interesting. After the imports, we define a struct for the request’s body. In line 16 you can see the pointer receiver we defined in the previous step. In line 31 you can see, that we using this pointer receiver whose variable name is simply h.

Everything else is pretty straightforward. We get the request’s body, declare a new book variable, merge the request’s body with this book variable, and create a new database entry. Then, we create a response with the book information.

Let’s add code to pkg/books/add_book.go

Get Books Handler

On this route, we are going to return all books from our database. This works now pretty fast, but as soon as you have bigger data to handle, better go for a pagination approach.

Let’s add code to pkg/books/get_books.go

Get Book Handler

Here, we just respond with only 1 book based on the ID which we get from a parameter.

Let’s add code to pkg/books/get_book.go

Update Book Handler

If we add a book, we also should have the option to update created books. This route is similar to the AddBook route we have coded earlier.

Let’s add code to pkg/books/update_book.go

Delete Book Handler

This is our last route in this article. Here, we delete a book based on its ID, but only, if the desired entry exists inside the database. We only respond with an HTTP status code.

Let’s add code to pkg/books/delete_book.go

Controller (again)

The routes are done. Now we need to modify the controller file once again. This time, we create a function called RegisterRoutesit’s pretty self-explaining what it does, right?

Do you remember the receiver pointer? Here we get the receiver pointer for our routes/handlers.

Let’s change the filepkg/books/controller.go from:

to:

Main File (again)

Also, we have to modify our main file once again. Before, we just initialized the database. But this time, we get its return and register our routes/handlers.

Let’s change the file cmd/main.go from:

to:

This is optional. Here we can set some scripts to simplify commands. For instance, we define a server script to run the application. So instead of running the application by go run cmd/main we run it instead by make server. This example is not good, since the actual command is pretty short, but imagine you would have to deal with longer commands.

Let’s add code to Makefile inside the root directory.

Everything is done! No coding anymore. Now, let’s run the application.

$ make server

or

$ go run cmd/main.go

The output should look like this. Besides the warnings, we can see, that our routes got settled up and the application runs on port 3000.

Now, we can test the two routes we have just created. We can test it, by using software such as Postman, Insomnia, or we simply run CURL commands.

POST: Add a new book

$ curl --request POST 
--url http://localhost:3000/books
--header 'Content-Type: application/json'
--data '{
"title": "Book A",
"author": "Kevin Vogel",
"description": "Some cool description"
}'

GET: Get All Books

Don’t forget, you can run GET commands also in your browser.

$ curl --request GET --url http://localhost:3000/books

GET: Get Book by ID

$ curl --request GET --url http://localhost:3000/books/1

PUT: Update Book by ID

$ curl --request PUT 
--url http://localhost:3000/books/1
--header 'Content-Type: application/json'
--data '{
"title": "Updated Book Name",
"author": "Kevin Vogel",
"description": "Updated description"
}'

DELETE: Delete Book by ID

$ curl --request DELETE --url http://localhost:3000/books/1

We are done! Great. Don’t forget, that I have uploaded this project on Github.

Thanks for reading this article about how to build a scalable but simple API in Go with Fiber. I hope, you could learn something new. Let me know if you have questions.

Cheers!

Leave a Comment