Instagram
youtube
Facebook
  • 2 years ago
  • 1433 Views

RESTful web service using Go and Gin

Yaman Birla
Table of Contents

 

Hello, tech geeks, Today we are going to learn about how to write a RESTful web service using Golang and Gin web framework (Gin).
In this tutorial, some familiarity with go and its tools is needed so, make sure, to have that ready with you. 
Gin simplifies the coding tasks related to web applications + web services however, today we are going to use gin as a router to route requests, retrieve requests, and marshal JSON for responses.

Prerequisites before jumping on to development:

  • An installation of Go 1.16 or later. For more info click here
  • A tool to edit your code. Any text editor you have will work fine.
  • A command terminal. Go works well using any terminal on Linux and Mac, and on PowerShell or cmd in Windows.
  • The curl tool. On Linux and Mac, this should already be installed. On Windows, it’s included on Windows 10 Insider build 17063 and later. 

API Endpoints

We are creating an API that enables users to access a shop selling vintage records from the past. Therefore, you'll need to offer endpoints that a client may utilize to download and add albums for users. Designing the endpoints is often where you start when creating an API.

The endpoints used in this tutorial are listed below:
 

/albums

GET - Retrieves a JSON list of all the albums.

POST - From request data given as JSON, add a new album.

 

/albums/:id

id GET - Retrieve an album using its ID; the album data is returned as JSON.

Create a folder or project directory in your system

To begin with, open the command prompt or PowerShell and change the directory to your home directory (go-workspace directory).

Create a folder named web-service-gin

Now move into the web-service-gin and add a go.mod file init:

As we created the mod file and main.go to writing our code.

The Data

In this tutorial we are not going to use any database to retrieve and store data however, we’ll store data in our memory means we will be creating the data.

So, we will do this with the help of Go struct.

Make a struct and its slice as given below:

// album represents data about a record album.
type album struct {
    ID     string  `json:"id"`
    Title  string  `json:"title"`
    Artist string  `json:"artist"`
    Price  float64 `json:"price"`
}

// albums slice to seed record album data.
var albums = []album{
    {ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
    {ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
    {ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}

Here, we added the data as vintage song records with their id, title, artist and price.

Below is our complete code:

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

// album represents data about a record album.
type album struct {
    ID     string  `json:"id"`
    Title  string  `json:"title"`
    Artist string  `json:"artist"`
    Price  float64 `json:"price"`
}

// albums slice to seed record album data.
var albums = []album{
    {ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
    {ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
    {ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}

func main() {
	router := gin.Default()
	router.GET("/albums", getAlbums)
	router.GET("/albums/:id", getAlbumByID)
	router.POST("/albums", postAlbums)

	router.Run("localhost:8080")
}

// function to respond with the list of all albums as JSON
func getAlbums(c *gin.Context) {
	c.IndentedJSON(http.StatusOK, albums)
}

func postAlbums(c *gin.Context) {
	var newAlbum album

	//BindJSON will bind the received JSON to our variable newAlbums
	if err := c.BindJSON(&newAlbum); err != nil {
		return 
	}

	albums = append(albums, newAlbum)
	c.IndentedJSON(http.StatusCreated, newAlbum)
}

func getAlbumByID(c *gin.Context) {
	id := c.Param("id")

	//loop over the albums for given id
	for _, a := range albums {
		if a.ID == id {
			c.IndentedJSON(http.StatusOK, a)
			return 
		}
	}

	c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})	
}

 

Let’s break down our code for better understanding:

 

Here we made a couple of functions that work as a handler to get, post and even retrieve a particular data.

 

getAlbums: 

  • it will help us return all albums. This getAlbums function creates JSON from the slice of album structs, writing the JSON into the response.
  • gin.Context is the most important part of Gin. It carries request details, validates and serializes JSON, and more.
  • Call Context.IndentedJSON to serialize the struct into JSON and add it to the response.
  • The function’s first argument is the HTTP status code you want to send to the client. Here, you’re passing the StatusOK constant from the net/http package to indicate 200 OK.

 

postAlbums:

  • Use Context.BindJSON to bind the request body to newAlbum.
  • Append the album struct initialized from the JSON to the albums slice.
  • Add a 201 status code to the response, along with JSON representing the album you added.

 

getAlbumsByID:

 

  • Context.Param to retrieve the id path parameter from the URL. When you map this handler to a path, you’ll include a placeholder for the parameter in the path.
  • Loop over the album structs in the slice, looking for one whose ID field value matches the id parameter value. If it’s found, you serialize that album struct to JSON and return it as a response with a 200 OK HTTP code.
  • As mentioned above, a real-world service would likely use a database query to perform this lookup.
  • Return an HTTP 404 error with http.StatusNotFound if the album isn’t found.

In the main function, we have added the router to request and retrieve responses with the help of these functions.

 

Before running the code make sure to run the following command to add the github.com/gin-gonic/gin module as a dependency for your module. 

Let’s run our code to check the API

Now from a different cmd run the following command

curl http://localhost:8080/albums

This will result in the following image:

However, if you open your browser and go onto localhost:8080/album

There you can also see your data information:

Boom! Our API is running, Now let’s use the POST and adding the data from ID that we created earlier:

 

Now post data, from a different cmd and add the following command:

 

curl -d "{\"id\": \"4\",\"title\": \"The Modern Sound of Betty Carter\",\"artist\": \"Betty Carter\",\"price\": 49.99}" -X POST http://localhost:8080/albums

Now let’s retrieve full albums to check our data has been added or not?

As we can see that our data has been added.

Now, let’s check our last get album method to retrieve specific data from ID:

In our getAlbumByID function there is the /albums/:id path. In Gin, the colon preceding an item in the path signifies that the item is a path parameter.

 

Well, Our API is working fine thanks for sticking to the last.

 

GitHub: https://github.com/cosmic-weber/Golang/tree/main/web-service-gin

 

 

 

 

Add a comment: