Table Of Contents


Creating Rest API in Go with Gin

Creating Rest API in Go with Gin

profile-image

Milan Poudel

December 8, 2022



Golang has become one of the most popular languages which is being widely used in the backend domain. Thanks to its simplicity and the features of concurrency, we have been able to create a performant monolith and microservices using Golang.


Note: Although the standard library of Golang is enough for us to create an HTTP API services, we will be using Gin as a framework in this post. Gin, which is really popular and widely used framework, will help us to handle routing, routes grouping, middleware, and other things.


Setting up a new project:


Let's get started, we will create a new folder named "goginrestapis" or anything as you like. Inside the folder, we will create a file named "main.go". Let's write a basic main function in the main.go file.


//main.go 

package main
import "fmt"
func main() {
    fmt.Println("Hello world")
}


Command to run main.go file


Let's run this file with a run command to check if everything is working.


go run main.go
// Output:
Hello world


Initializing "Go Modules":


To install the packages or libraries, we should initialize go modules so we can manage and organize the packages or libraries that we have installed in our Go Project. Let's initiliaze it: We can give it any name as we like:


go mod init goginrestapis



With this, now we will able to install Go Gin in our project. This will install go gin package in our project.


 go get -u github.com/gin-gonic/gin


Simple HTTP GET request with GIN:


Let's use "gin" in our project now in our main file:

package main
import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func main() {
    //initializing a gin router 
	r:= gin.Default()
   //just a simple ping request to check if gin is working and can send response
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "pong",
        })
    })
}



Here, we did the following things:


  • We initialized a router from gin with all it's default middleware and loggers


  • Then we created a simple "/ping" route just to check if we are getting back response and gin is working. Here , the controller excepts a function that has hat takes a *gin.Context parameter.



Our simple Todo struct:


Let's take this further. We will create a todo struct that we will be returning as a response.


type todo struct {
	ID        string `json:"id"`
	Title     string `json:"title"`
	Completed bool   `json:"completed"`
}


Here the structure looks a simple struct with the properties. The tags we see (json:"id", json:"title", json:"completed") represents JSON tags. They specify the JSON key names to be used when encoding or decoding JSON data.


We will create just a simple get route for now to send back the todos as a response.


// created slices of todo
var todos = []todo{
	{ID: "1", Title: "Learn Go", Completed: false},
	{ID: "2", Title: "Build a RESTful API in Go", Completed: false},
	{ID: "3", Title: "Build a React app", Completed: false},
}


Now, let's send this slice of todo wich id todos slice as a response.


func getTodos(context *gin.Context) {
	context.IndentedJSON(http.StatusOK, todos)
}


Here context.IndentedJSON(http.StatusOK, todos) will convert or marshal the slice of todos into the JSON format


Adding "getTodos", a simple handler with a "GET" request:


Putting it all together in our main file:


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

type todo struct {
	ID        string `json:"id"`
	Title     string `json:"title"`
	Completed bool   `json:"completed"`
}

var todos = []todo{
	{ID: "1", Title: "Learn Go", Completed: false},
	{ID: "2", Title: "Build a RESTful API in Go", Completed: false},
	{ID: "3", Title: "Build a React app", Completed: false},
}

func getTodos(context *gin.Context) {
    // will convert above slice of todo into JSON format so our client can receive
	context.IndentedJSON(http.StatusOK, todos)
}

func main() {
	r:= gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "pong",
        })
    })
	r.GET("/todos", getTodos)
	r.Run("localhost:8080")
}


With this, when we send a "GET" request to the route "/todos", we will be getting back the array of todos as a data.



Adding "newTodo" Controller with POST request:


Let's add another simple "POST" request here to add a new todo data.


func addTodo(context *gin.Context) {
	var newTodo todo
    // here BindJSON receives and parses the request body// and maps the parsed json values to the field of newTodo struct
    if err := context.BindJSON(&newTodo); err != nil {
		return
	}
   // adding or appending a new todo the lists we already have
	todos = append(todos, newTodo)
	fmt.Println("New todo added: ", newTodo)
	fmt.Println("All todos: ", todos)
    // sending back the todos slices after adding new todo as converted json data
	context.IndentedJSON(http.StatusCreated, todos)
}


What does "context.BindJSON" does?


Here, within addTodo controller, we parsed the request body which will be in json format using context.BindJSON and then map our json values to the corresponding fields of newTodo struct.


After mapping , we will append this newTodo struct data to our todos data and will send back new todos as a response.


Putting it all together in our main file, it will look like this.


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

type todo struct {
	ID        string `json:"id"`
	Title     string `json:"title"`
	Completed bool   `json:"completed"`
}


var todos = []todo{
	{ID: "1", Title: "Learn Go", Completed: false},
	{ID: "2", Title: "Build a RESTful API in Go", Completed: false},
	{ID: "3", Title: "Build a React app", Completed: false},
}


func getTodos(context *gin.Context) {
	context.IndentedJSON(http.StatusOK, todos)
}


func addTodo(context *gin.Context) {
	var newTodo todo
	if err := context.BindJSON(&newTodo); err != nil {
		return
	}
	todos = append(todos, newTodo)
	fmt.Println("New todo added: ", newTodo)
	fmt.Println("All todos: ", todos)
	context.IndentedJSON(http.StatusCreated, todos)
}

func main() {
	router := gin.Default()
	router.GET("/todos", getTodos)
	router.POST("/todos", addTodo)
	router.Run("localhost:8080")
}

Programming | Coding | Learning

Subscribe to learn about new technology and updates. Join over 1000+ members community to stay up to date with latest articles.

© 2024 Code With Milan. All rights reserved.