Introduction to Gin Middleware
What's going on guys? In this video, we're going to start working with middlewares using the Xin HTTP framework. We are going to add three middlewares to our API in order to support authorization, logging, and debugging.
And if you want to learn data science with Python, there is a link in the description below, and you can also download a Go cheat sheet. There is a link in the description below the video as well. Remember to subscribe to the channel and let's get started.
Default Middleware: Logger and Recovery
Okay, this is the API that we've been working on using Gin. We created a couple of endpoints. The first endpoint is using the GET HTTP verb to get the list of existing videos, and we also created an endpoint to handle the POST HTTP request on this URI. These endpoints are using the controller. Let's take this as an example, and the controller is using a service to delegate the operation. In this case, for the FindAll function, we are calling the FindAll function from the service, and within the service, the FindAll function is returning the slice of videos that is this one that we declared here within this struct.
Okay, let's go back. If we go here again, we will see that you're using these two middlewares that are actually global middlewares: Logger and Recovery. If we go back here, what we can do is we can create a new Gin instance, and we can declare these two middlewares like this: gin.Recovery. And that's the first global middleware that was created by default. And we can also do server.use(gin.Logger). And doing this, we are doing the same that if we use the default function here that includes these two middlewares or we can also do like this: server.use(Recovery, Logger). And let's change this right here. Okay.
Creating a Custom Logging Middleware
First, let's say that I want to change the logger and I want to customize the format of the log. So what we're going to do is I'm going to create a custom middleware within a new folder. Let's go ahead, middlewares, and I'm going to create a new file that's going to be logger.go. And here the package is going to be middlewares.
Then we create a function. I'm going to call it Logger and this function is going to return gin.HandlerFunc. This is the type that is expected for all the middlewares. And here we're going to use a special function provided by Gin. Here, return gin.LoggerWithFormatter. This one, where we can pass another function to customize the format of the log.
Okay, if we go here, we're going to see that LoggerWithFormatter is going to create an instance of a logger middleware with the specified log format function that is this one, type LogFormatter, that is actually a function. Let's go back here. And this LogFormatter is the parameter that we need to pass. Okay, close this.
So this is going to be an anonymous function that is going to receive a param and the type is gin.LogFormatterParams, like this, and this function returns a string. And here we need to return fmt.Sprintf and here we need to pass two parameters. The first one is going to be the format of the log and then we want to use the param here, this parameter that is going to include different attributes from the request: the client IP, the method, the path, the status code, the latency, and so forth.
So here I'm going to add three attributes from the request that I want to include as part of the log. So param.ClientIP is going to be one of them. Then we can include param.TimeStamp and we can apply a format to that timestamp. I'm going to use this one. And we can add the method GET or POST, param.Method. That's ready. The URI, param.Path, the status code, param.StatusCode, and param.Latency. Okay, these are part of the request, and some of those are part of the response, like these two.
Okay, this first element will be the client IP. I'm going to include it like that. And the second one, I'm going to include it here in brackets, that is going to be the timestamp. Then I'm going to put the method, the HTTP method here. The next one is going to be the path. The next one is going to be the status code. I'm going to close it as a decimal. And then the latency. And I'm going to add a new line.
Configuring and Testing the Custom Logger
Okay, let's go back and let's add that middleware. So it's going to be middlewares.Logger. And let's run this. Go run.
Now, let's go to Postman and let's run a couple of requests. So the first string here is the local IP address. This is localhost. Here is the date. This is the HTTP verb. Here is the status code, and this is the latency in milliseconds. So basically, this is the format, and here is how it looks when we actually run and we apply that middleware. So if I go back and I execute the post request, we're going to see that we have a new line. The only difference here is the POST HTTP method that is included here.
Writing Logs to a File
We can also change the output of the log so we can use either a standard output or we can use a file. So let's create a function to set up the output. And if you want to use a file, we can create a file using Go's library os.Create and we pass here the name of the file: gin.log. And this is going to return either a pointer to a file or an error. We are going to ignore the error for now.
And here we can assign a default writer to gin.DefaultWriter and we can assign a multi-writer, io.MultiWriter, and we can pass either the file or the file and the standard output, os.Stdout. So let's call this function from the main function here.
And let's run this. And now let's run a couple of requests. If you execute the GET operation, we're going to see that we get the output here. And here on the left side, we're going to see the gin.log file that is going to include that output as well. And let's run a POST request. And again, we have this line here in the standard output, and we get the same output here in the file. Okay, let's close this.
Implementing Basic Authorization Middleware
Okay, now let's start working on a new middleware. It's going to be a security middleware for authentication, actually for authorization. So this is going to be basic_auth.go. The package is going to be middlewares and I'm going to create the function BasicAuth. This is going to return, as any other middleware, gin.HandlerFunc. I'm going to import Gin. Like that.
And this will return a middleware provided by Gin, this one, BasicAuth. And this BasicAuth is going to receive a map, and that map is going to include the usernames that we are going to authorize as the key and the passwords for those users as the value of the map. So this is gin.Accounts, and let's say that we want to authorize a user with the username pragmatic and the password reviews.
So if we enter here to this middleware, BasicAuth returns a basic HTTP authorization middleware, and it takes a map as an argument where the key is the username and the value is the password. And let's use this BasicAuth middleware in our API. So we can use it here, middlewares.BasicAuth, like that. And let's run the server first.
Now, let's run a couple of requests. And here we can see that we get a 401 Unauthorized. The same here. So we need to pass the authorization username and password. So this is Basic Auth, and here we are passing pragmatic and reviews. And if you run this now, we're going to get a 200.
Understanding Basic Auth Encoding
And here with Postman, we can generate the code in multiple languages. We can generate it in Go, for example, like this, and we can run it. So let's do that. I'm going to copy this. I'm going to create a new file, let's say test.go. All this. And this is the encoding of the username and the password. This basically you can generate this by doing here for example... this is an online encoder in base64. So this is pragmatic:reviews, this is username:password. And you encode in base64 and you get this string. Okay, if we run this, we're going to see that we're going to get the same value here. Okay, if I run this... I'm going to open a new terminal. go run test.go. Okay and we get that 200 here. Let's go back.
Using gin-dump for Debugging
Okay, and the last middleware is going to be a middleware that is going to help us to develop our application, to debug our application, and it's called gin-dump. So I'm going to include it here. It is github.com/tpkeeper/gin-dump. I am going to assign an alias here, gindump. And we can add it here to the list of middlewares here. It's going to be gindump.Dump(). And if we run this, we're going to see the output. Now, if I run a request, we're going to see that the output is going to include more information here. Okay.
That's pretty much all I have for today. Thank you guys for watching. Remember to subscribe to the channel, and remember to download the Golang cheat sheet. And I'll see you in the next video. Take care. Bye.