Introduction to the Go Gin Framework
Hi everyone, it's Ellie from tutorialedge.net and in this tutorial, we're going to be looking at the gin-gonic/gin framework for writing HTTP web applications in Go. The Gin framework is immensely popular and has gained over 20,000 stars on GitHub, and I'll leave a link to where you can see that in the description below. And as always, if you find this tutorial useful at all, then please leave a like and subscribe to my channel for more programming content. I'm currently pushing for 5,000 subscribers, so every subscriber counts.
Project Setup with Go Modules
Okay, so let's get into the code. So I've opened up Visual Studio Code here, which is my editor of choice. Now I've created a really simple main.go file which simply prints out hello world, and we can test that that's all works by calling go run source/main.go. Nice and simple. Now we're also going to be using Go modules in this tutorial, and I know that's the new feature that's just been released in version 1.11 of the language. Now in order to initialize this project, we'll have to do go mod init like so, and that creates a new go.mod file. Okay, so let's open up our main.go file and start programming.
Creating a Simple GET Endpoint
Now the first thing we're gonna want to do is to import our gin-gonic framework. So at the top, let's add a couple of parentheses and we're going to do github.com/gin-gonic/gin like so. And just below this, we're going to want to start using the framework. Now just to get us up and running really quickly, and we're going to use gin.Default(). And we're going to do a really simple r.GET request or r.GET endpoint. This is just going to be for the root endpoint, like so. Now we want to define this by passing in the path and then an anonymous function which will take in the gin context, and it will return a JSON string with 200 status and gin.H, and we're going to do a message and hello world like so. Save that and then just at the bottom, we're going to want to listen and serve this on port 8080 by calling r.run().
Running the Server and Inspecting Logs
Next we want to do is really quickly fix a wee typo here by adding comma and we want to run this by calling go run source/main.go. Now that will go ahead and it will start up our gin HTTP framework and a lesson on port 8080. Now if we show over to a browser and we hit localhost port 8080, you can see that the JSON returned when I hit this endpoint is message and hello world as expected. And if we have a look at the terminal output for our incredibly simple program, you can see that it gives us the date and the time that this request is made. You can see the HTTP status code that was returned and we can see the amount of time that the request took to be served with. Now we can also see the path and we can see the verb used to hit our application. Now for its effectively about 10 lines of code, is an incredible amount of information given to us with a very low additional work needed.
Refactoring the Handler Function
Now that we've got a really simple example up and running, let's try and expand this further and actually create something that would look more like a production-ready application. Now the first thing I'm going to do is I'm going to get rid of this anonymous function and I'm going to put it as its own function up here. I'm also going to give it a name, so I'm going to say a homePage and I'm going to call just in here homePage like so. So that will stop everything being done within our main function, and we can expand this out to include things from different packages should we wish to. As always, let's assess these things. So every time we make a change, we'll test it and we'll ensure that the behavior is as expected and nothing has changed. And as you can see, everything is still working as expected.
Adding a POST Endpoint with Postman
So we've got a really simple GET endpoint exposed within our application. But typically in production-level APIs, you'll see things exposed on all the various other HTTP verbs such as POST, PUT, DELETE, PATCH and so on. So let's now see how we can expand our example and add these various different endpoints into our application. Now the first one I'm gonna do is a POST endpoint. So I'm gonna keep the same path and do r.POST and I'm going to create a new function and we're going to call this postHomePage. And just up here above our main function, I'm going to actually define this postHomePage function. So again, it's going to take in the C gin context and I'm going to return JSON as well. So JSON, 200, gin.H and I'm gonna change the message up just a little bit. So postHomePage like so. Add the trailing comma and save that. And let's try restarting our application. So go run source/main.go again, and everything has started as expected. Now in order to test our new post-based endpoint, I'm going to open up a program called Postman, and again I'll be leaving a link to where you can get this in the description below. Now Postman is essentially a REST client that is incredibly popular with web developers and programmers all across the world, so it's something that I feel that it would be very worthwhile getting to know. Now as you can see, I've entered the localhost port 8080 URL into my input form, and I've specified I'm going to have a static GET there. Now when I hit this request, you can see that the message returned is our standard hello world one, which is exactly the same as we saw in the browser. Now if I change this verb to POST and I hit the same request, you can see that the message returned is our newly added postHomePage response, which was defined within our postHomePage function like so.
Handling Other HTTP Verbs
And as you can see within our terminal output, we now have three different requests. And so one was the original GET request and the last one which we just sent there was our POST request. Now so far we've been successful in creating a really simple API that features a router and exposes both a GET and a POST endpoint within that API. Now you could do the same for all of the other HTTP verbs such as PUT and DELETE, PATCH, HEAD and our OPTIONS, and again you would just specify the function you wish to route that particular API request towards. So that just about covers the basics.
Parsing URL Query String Parameters
Now let's try and expand this further and try and do some more complex things such as query strings, path parameters and trying to retrieve the body of any POST requests, which are very typical tasks that you would have to do within most APIs. So let's first of all try and look at how we would handle query strings within a REST API. So to do that, I'm going to create a new endpoint. It's gonna be accessed over the GET HTTP verb and I'm going to call this query. Now I'm going to create a new function called queryStrings and effectively what this is going to do is it's going to take in any /query requests and it's going to parse query strings which look something like this. So name=elliott and age=24. Now I'll then be able to take these from our path or query and I'll be able to then use these to manipulate any responses sent back from that particular endpoint. So just above our main function, we're going to define that query strings function. Now again, this is going to take in the pointer to the gin context and just in here we're going to do the following. So name := c.Query("name") so this will take in any sort of name=elliott. And then we're going to do age := c.Query("age") like so. And finally I'm going to return a response object. So just within here I'm going to do the following. So instead of returning a message, I'm going to want to return the name and I'm going to want to return age. Perfect. So let's try run that. So go run source/main.go as we had before and let's open up Postman once again and add query and then our query string parameters. So name=elliott and age=24 like so. I'm now going to send this and as you can see the JSON returned is exactly what we expected. So it's been able to parse both the name and the age from my query string here. Now if this was a more fully-fledged API, it would probably go off to insert them into the database or do some form of manipulation with whatever query strings were passed, but for now this just shows you how to really simply parse those query string values.
Parsing URL Path Parameters
So let's now have a look at how you would do path parameters as opposed to query string parameters. Now let's come back into our program and we're going to define a new endpoint. And again it's going to be the similar format to our query string parameters but with this we're gonna expect the following. So it's /path and instead of having the query string, we're going to say okay I want the name here and the age here. Now to do that, we're going to want to do the following. So change this to path, and then we're going to specify :name and :age like so. And because we can't use the same function, we're going to call this pathParameters. Copy this and let's create that function now. So func pathParameters, again taking in the pointer to the gin context. And then we want to do the following so name := c.Param("name") and age is going to be again equal to c.Param("age"). So this is incredibly similar to our query strings, except instead of using c.Query, it's using c.Param. And again we're going to steal that's JSON object and we're going to copy and paste that in here because I'm feeling quite lazy today. So again, we've just added a new endpoint to our REST API, but let's now test these things. So go run source/main.go and we're going to open up our Postman once again. And we're going to add this new path parameter and we're going to say test-name and we're going to add the value 100 here just to sort of mix things up a bit. Now I'm going to send this GET request and as you can see it has been able to successfully parse these path parameters from my URL and it's been able to print them back in JSON format to me as expected. So everything is now working with both our query strings and our path parameters.
Reading the POST Request Body
So the final thing I want to cover with you is how you can read in the post request body within a function. Now we're going to modify our existing post endpoint so that it can read in any text value or any value we pass in through the body of our request in Postman. Now let's go up to our postHomePage function and the first thing we're going to do is specify body := c.Request.Body and we're then going to do the value, err := ioutil.ReadAll(body). And if err does not equal nil, then we are just going to print out the error for now, but you should typically return a response of type error. And we're then going to pass into our message, instead of Hello, what we're going to do string(value) like so. Save that and let's try run this again. So go run source/main.go and let's try hitting this post request with our tested data. So as you can see, test or hello world both successfully respond with the JSON that we would have expected, which is the message and the value of our POSTer body.
Conclusion and Next Steps
So that's all I'm going to cover in this tutorial for now, but we are going to look at things like testing and productionizing this API in our future tutorial. Now if you enjoyed this and found it useful, please leave a like and let me know in the comment section down below. And if you have any further questions, I'd be happy to hear them down in that comment section as well. And as always, subscribe to my channel for more programming content. Cheers.