The Gin Framework - REST API's with Golang

REST API's are rad. Golang is rad. What if I told you that you can use Golang to make REST API's using the Gin framework?

The Gin Framework - REST API's with Golang

Continuing on my series on reasons why Golang rocks, let's talk about the Gin framework!

We already covered how to use Golang to make calls to REST API's. Gin is a library that let's us build REST API's!

The Gin Framework - Setting up the server

The code to set up a Gin server is dead simple. You simply call the gin.Default() function to create the server object and run server.Run(":<port>") to start it. Between creating the server and running it, you will add all of your routes, which we will cover below.

func main() {
	fmt.Println("[-] Starting up server on port 3000...")
	server := gin.Default()
	// routes go here
	server.Run(":3000")
}

Creating your first endpoint

REST API's are divided up into endpoints. The Gin framework has an awesome way of subdividing your API into endpoints based on method (GET, POST, etc.) and functions that are passed as callbacks to those methods. Each endpoint will have a method, a route and a callback, illustrated with a simple GET endpoint below:

func handleGet(ctx *gin.Context) {
	ctx.JSON(200, gin.H{
		"message": "hello world!",
	})
}

func main() {
	fmt.Println("[-] Starting up server on port 3000...")
	server := gin.Default()
	server.GET("/helloworld", handleGet)

	server.Run(":3000")
}

We set up the endpoint with server.GET("/helloworld", handleGet), which creates a server with the route /helloworld and a handler function handleGet. This function takes a pointer to a gin.Context object, which will allow us to structure the response and, as we will see later, access the body of the request.

We use the ctx.JSON() function call to send a JSON response with a status code 200. The gin.H{} object is a generic interface to send a JSON response to a request in Gin.

Let's test this endpoint with Postman!

Using Postman to test your endpoints

Postman is every web developer's best friend. You can use it to test API endpoints, whether they be API's that you're developing or third party API's, to get a feel for how you would programmatically call those endpoints, how the data is mapped, etc. It comes with a nice (if complex) GUI that allows you to save your queries for future use.

Needless to say, I use this tool almost daily, especially when developing REST API's.

With our web server started up, let's construct a request in Postman by first choosing the request method and inputting the path to the endpoint. Then we run the request and get the following output.

Creating a POST endpoint and extracting data

Now, GET method endpoints are fairly easy. You either pass data in the URL (which is pretty easy to parse) or you just won't have data to begin with. POST endpoints that have to handle JSON data are a little bit more complicated... but not much.

First, let's create a struct to handle our data. To keep it simple, let's say we're just dealing with a message field representing a string.

type postReq struct {
	Message string `json:"message"`
}

Let's create a function to pass to the POST endpoint at the /message route called handlePost(). This function takes a gin.Context{} object, just like the GET request route above.

func handlePost(ctx *gin.Context) {

	tobind := postReq{}
	err := ctx.BindJSON(&tobind)
	if err != nil {
		ctx.JSON(501, gin.H{
			"message": "Body did not bind properly...",
		})
	}
	fmt.Println(tobind.Message)
	ctx.JSON(200, gin.H{
		"status":  "success!",
		"message": tobind.Message,
	})
}

The biggest difference is that in this POST request, we're passing data in our request. We use the ctx.BindJSON() function to pull the request body out and bind it to an empty struct ( tobind, which is an instance of our custom postReq{} object) which we will then parse out, print and return as part of the response, again using the ctx.JSON() function.

Then our entire main function will look like this:

func main() {
	fmt.Println("[-] Starting up server on port 3000...")
	server := gin.Default()
	server.GET("/helloworld", handleGet)
	server.POST("/message", handlePost)

	server.Run(":3000")
}

If we run this in Postman, changing our method from GET to POST and giving it an input body (top pane, underneath the request URL) that's formatted correctly, we'll see the following return object in the bottom pane.

Conclusion

I've written API's in Rust, C, Javascript and Python previously, and I honestly don't think I've ever seen a language or framework handle fast, feature rich API's like Golang's Gin framework. It's incredibly easy to develop a complex and fully-featured REST API quickly and efficiently, and I really don't know if I'll ever go back.