Table Of Contents
Creating Rest API in Go with Gin
Milan Poudel •
December 8, 2022
Table Of Contents
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.
Made with ❤ by
Milan Poudel