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: