Introduction
What's going on guys? In this video we're going to start working with the Gin HTTP framework by building a simple REST API. And if you want to learn Data Science with Python check out DataCamp; there is a link in the description below this video. You will get certificates showing your progress and you can include them as part of your LinkedIn profile. You can download the Golang cheat sheet; there is a link in the description below this video. Remember to subscribe to the channel and let's get started!
Project Setup & Server Initialization
Okay, first I'm going to initialize the project: go mod init "gitlab.com/..."... and I'm going to install the Gin library: go get github.com/....
Okay, and let's start by creating a new file, and the file will be server.go.
Initializing the Default Gin Server
And the package will be main and I'm going to create a main function. And here I'm going to initialize a new server using the Gin library: gin.Default(). This is the default server. And if we go here, we're going to see that this server is going to include by default a couple of middlewares. In this case, we have a Logger that is going to output information about the requests, we're going to see that in a second. And then we have this Recovery function that is going to recover from any panics and it's going to write the 500 HTTP code if we get any panic condition. So I'm going to close this and I'm going to keep working on the server.
Creating a Basic GET Endpoint
And let's create our first endpoint. So let's create a get endpoint, server.Get(...). Let's call it /test, and let's create an anonymous function. And here we need to pass the context. There is a special struct in Gin that is the Context, so we can specify it like this: ctx *gin.Context like this. And the context includes the HTTP request, a writer that is going to be the HTTP response at the end, and a bunch of other attributes. Let's go back.
And here we need to include the body of this function. We're going to return a JSON: ctx.JSON(...). The HTTP code is going to be the first parameter, in this case it's gonna be 200. And here we can return the body of the response, gin.H{...} and here, this struct, and here we can pass the JSON object. This will be message and the value is gonna be OK!!.
Running and Testing the First Endpoint
Let's run this, go run server.go. And yeah, before running it I forgot to initialize the server, this will be server.Run(...) and I need to pass the port, that's going to be 8080 in this case. Let's say... okay, now I can run the server. I forgot to add a comma here, that's the issue.
Okay, let's run it. And as we can see here, the server is going to output some debugging text. In this case, it's saying that we can use these two ways to change from the debug mode, that is the current mode or the default mode when we start the server, and with this we can switch from debug to production mode. And it's basically saying that is listening on port 8080 and that this is the only endpoint available for this HTTP verb and this is the URI. Okay, let's go to Postman and let's run the first request. And the port is 8080 actually. Let's try this and we get the response. And here we get a pretty nice output including the response time, here we have the verb, and here we have the URI. Okay, I'm going to stop this.
Structuring the API: The Video Entity
We're going to create an entity, a service, and a controller. So let's get started by creating the entity. Let's create a new folder, entity, and I'm going to create, let's say that we want to manage video information. So it's going to be video.go. The package is gonna be entity.
And I'm going to create our struct: type Video struct... It's gonna have a title that it's gonna be a string, a description that's gonna be a string, and a URL that's gonna be a string as well, just to keep it really simple. And here we need to specify the details for the JSON serialization. We are going to use title for this property, the next one is going to be description, and for the last one it's going to be url. Now I'm going to create a service.
Building the Video Service Layer
service and it's going to be video service file video-service.go. The package service and the type here... I'm going to create an interface and I'm just going to create two functions: one to save the videos and another one to get the list of the existing videos. type VideoService interface... I'm going to include a function to save the video, and I'm going to return the new video. And the FindAll function that is going to return a slice of videos, like that.
Okay, now I'm going to create a struct that is going to implement that interface and it's going to include as a property a slice of videos, like that. And I'm going to create a constructor function to get a new instance of this VideoService and it's going to return an implementation of the interface that we created here. It's going to return a pointer to this structure.
Okay, and now let's get started working on these two functions. We need to specify the struct to make it implement the interface like that, and the same for the FindAll function. And we are going to use this slice to store the videos, so the FindAll function is going to return that slice: return service.videos. And here we are going to append the new video to the slice, so it's going to be service.videos = append(...) and then we pass the slice first and then the new element that's gonna be the video. I forgot to add the name of the argument like this, and this is going to return the video. Okay, and now let's start working on the controller.
Building the Video Controller Layer
The controller basically is going to include all the handlers for the two HTTP verbs that we are going to handle. We're going to handle GET to get the list of existing videos and POST to create a new video. So let's create a new folder, and it's gonna be video-controller.go. The package it's gonna be controller and we're going to have an interface type VideoController interface... and it's going to include two functions: a FindAll function that is going to return a slice of videos, and a Save function. In this case, we're going to receive a Gin Context and we are going to use this context to access the data that comes with the HTTP request. So this is gin.Context. I'm going to use that structure.
Okay, now let's create the struct that is going to implement that interface, let's call it controller. Okay, and this structure is going to include a service and it's going to use that service to delegate these operations. And this is going to be service service.VideoService. Okay, now we need to add a constructor function, and this constructor function is going to receive the service, so we need to add this argument. And this is going to return a VideoController, so here we need to return this struct and we're going to pass the service.
Okay, and now let's start working on these two functions. And here I'm going to pass the controller struct to implement the video controller interface. This is going to be a pointer to the controller struct, and the same for the Save function. And this is just going to delegate to the service, c.service.FindAll(). And here we need to declare a video variable that's going to be of type entity.Video and we need to extract from the context the payload that is going to be a JSON including the Video struct. So ctx.BindJSON(...), this is the function that we need to use here, and a pointer to the variable where I'm going to unmarshal the video. And here I'm going to delegate to the service. Now this is actually c.service.FindAll() and here... c.service.Save(...) and we need to pass the video. And yes I forgot to add this here in the interface. We're going to return the video every time that we store a new video. Here... and I'm going to return the video. Ok, really simple, just two functions.
Wiring Endpoints to the Controller
And now let's move on to the server. I'm going to remove this one and I'm going to create another endpoint. It's gonna be server.GET(...) and it's going to be /videos and an anonymous function that is going to handle that HTTP verb. Here we need to declare the context that is a pointer to gin.Context struct. And here I'm going to declare a couple of variables. The first one is going to be videoService, this one will be service.VideoService. And here I'm going to use the constructor function like that. And the next one is going to be the videoController, controller.VideoController, and it's going to be controller.New() and I need to pass the video service here.
Okay, and here within this GET handler we need to use the controller, and here we're going to use the FindAll function. And here we need to use the context and the JSON function of the context to return this list of videos. So this is ctx.JSON(...) and we need to pass the HTTP response code, that's gonna be 200 in this case, and now videoController.FindAll(). And that's that.
And we are going to add another HTTP verb that is going to be POST to create a new video. And here we need to replace this FindAll() function by the Save() function and I'm going to pass the context here. And that's what I need. Okay, this is gonna be videos instead of posts (sorry about that). Yeah, now this makes sense. Okay, let's run this.
End-to-End API Testing with Postman
Okay, now let's go to Postman and let's run a couple of requests. Yeah, the first GET request is going to return an empty array so this makes sense. And now let's create a new video. So we're going to pass the title, the description, and the URL like that. Let's run this, and we get the title that we created. And if we execute the GET operation, we're gonna get the element. Yeah, we get the array including the element that we just created. And let's create another one. And as we can see here, we have our first version, our initial version of the video API up and running. And here we can see the details with the response time, the HTTP method that we are executing, and the URI. GET, POST, etc. And here we have the HTTP response here highlighted in green.
Conclusion
Okay guys, that's pretty much all I have for today. Thank you for watching and I see you in the next video. Take care, bye!