1. Introduction
In Go,net/http
Packages provide a powerful and flexible standard HTTP library that can be used to build web applications and handle HTTP requests. This package is part of the Go language standard library, so all Go programs can use it directly. Since there is alreadynet/http
Why does such a powerful and flexible standard library still appear likeGin
This makes it convenient for us to build third-party libraries for web applications?
Actually, it'snet/http
, which provides basic HTTP functionality, but its design goal is to simplify and versatile, rather than provide advanced features and convenient development experiences. When handling HTTP requests and building web applications, you may encounter a series of problems, which also createsGin
The emergence of such a third-party library.
Below we will introduce a series of scenarios, through comparisonnet/http
andGin
The different implementations of the two in these scenarios will further illustrateGin
The necessity of the existence of the framework.
2. Complex routing scenario processing
In actual web application development, the scenario of using the same route prefix is very common. Here are two more common examples.
For example, when designing APIs, the API may be updated and improved over time. To maintain backward compatibility and to allow multiple API versions to coexist, a similar/v1
、/v2
Such routing prefixes are used to distinguish different versions of APIs.
There is another scenario where a large web application is often composed of multiple modules, each module responsible for different functions. In order to better organize the code and distinguish the routing of different modules, module names are often used as routing prefixes.
In both scenarios, it is likely that the same routing prefix will be used. If usingnet/http
To frame web applications, the implementation is roughly as follows:
package main import ( "fmt" "net/http" ) func handleUsersV1(w , r *) { (w, "User list in v1") } func handlePostsV1(w , r *) { (w, "Post list in v1") } func main() { ("/v1/users", handleUsersV1) ("/v1/posts", handlePostsV1) (":8080", nil) }
In the example above, we use it manuallyto define different routing processing functions.
The code example doesn't seem to be a big problem, but because there are only two routing groups, if the number of handlers increases, the number of processing functions will also increase, and the code will become more complex and verbose. And each routing rule needs to manually set the routing prefix, as in the examplev1
prefix, if the prefix is/v1/v2/...
Setting up this way will lead to unclear code structure, complicated operations, and easy to make mistakes.
But by comparison,Gin
The framework implements the function of routing packets, let's take a look at itGin
Framework to implement this function:
package main import ( "fmt" "/gin-gonic/gin" ) func main() { router := () // Create a routing group v1 := ("/v1") { ("/users", func(c *) { (200, "User list in v1") }) ("/posts", func(c *) { (200, "Post list in v1") }) } (":8080") }
In the above example, byCreated a
v1
When we set routing rules for routing prefixes, we do not need to set routing prefixes, and the framework will automatically assemble them for us.
At the same time, rules with the same route prefix are also maintained in the same code block. Compared withnet/http
Codebase,Gin
Make the code structure clearer and easier to manage.
3. Middleware processing
In the process of web application request processing, in addition to executing specific business logic, some common logic is often required before this, such as authentication operations, error processing or log printing functions. These logics are collectively called middleware processing logic, and are often indispensable.
First of all, for error handling, some internal errors may occur during the execution of the application, such as database connection failure, file reading errors, etc. Reasonable error handling can prevent these errors from crashing the entire application, but instead inform the client with appropriate error responses.
For authentication operations, in many web processing scenarios, it is often only after user authentication that they can access certain restricted resources or perform certain operations. At the same time, authentication operations can also limit user permissions to avoid unauthorized access by users, which helps improve the security of the program.
Therefore, a complete HTTP request processing logic is very likely to require these middleware processing logic. And theoretically, frameworks or class libraries should have support for middleware logic. Let's take a look at it firstnet/http
How to implement it:
package main import ( "fmt" "log" "net/http" ) // Error handling middlewarefunc errorHandler(next ) { return (func(w , r *) { defer func() { if err := recover(); err != nil { (w, "Internal Server Error", ) ("Panic: %v", err) } }() (w, r) }) } // Authentication and authentication middlewarefunc authMiddleware(next ) { return (func(w , r *) { // Simulated authentication if ("Authorization") != "secret" { (w, "Unauthorized", ) return } (w, r) }) } // Handle business logicfunc helloHandler(w , r *) { (w, "Hello, World!") } // in additionfunc anotherHandler(w , r *) { (w, "Another endpoint") } func main() { // Create a router router := () // Application middleware, register processor handler := errorHandler(authMiddleware((helloHandler))) ("/", handler) // Application middleware, register another request processor another := errorHandler(authMiddleware((anotherHandler))) ("/another", another) // Start the server (":8080", router) }
In the above example, wenet/http
PassederrorHandler
andauthMiddleware
The two middlewares implement error handling and authentication functions. Next, we look at line 49 of the sample code and we can find that the code adds error handling and authentication operation functions to the original processor through the decorator mode.
The advantage of the implementation of this code is that multiple processing functions are combined through the decorator mode to form a processor chain, which realizes error handling and authentication and authentication functions. Without needing to handle every functionhandler
Adding this part of the logic into it makes the code more readable and maintainable.
But there is also a very obvious disadvantage here, this function andNot a framework for usIt is achieved by ourselves. We add a new processing functionhandler
, all need to do thishandler
Decorate and add error handling and authentication operations to it, which increases the burden on us and is also prone to errors. At the same time, the requirements are constantly changing. It is possible that some requests only require error processing, some requests only require authentication operations, and some requests require both error processing and authentication operations. Based on this code structure, it will become increasingly difficult to maintain.
By comparison,Gin
The framework provides a more flexible way to enable and disable middleware logic, which can be set for a certain routing group without having to set individually for each routing rule. The following example code is shown below:
package main import ( "/gin-gonic/gin" ) func authMiddleware() { return func(c *) { // Simulated authentication if ("Authorization") != "secret" { (401, {"error": "Unauthorized"}) return } () } } func main() { router := () // Add Logger and Recovery middleware globally // Create a routing group where all routes in the group will apply authMiddleware middleware authenticated := ("/") (authMiddleware()) { ("/hello", func(c *) { (200, "Hello, World!") }) ("/private", func(c *) { (200, "Private data") }) } // Not in the routing group, so no authMiddleware middleware is applied ("/welcome", func(c *) { (200, "Welcome!") }) (":8080") }
In the above example, we("/")
Created a name calledauthenticated
and then use the routing groupUse
Method, enable the routing groupauthMiddleware
middleware. All routing rules under this routing group will be automatically executedauthMiddleware
Implemented authentication operation.
Relative tonet/http
The advantage of this is that it does not need to be for eachhandler
Decorate and add middleware logic. Users only need to focus on the development of business logic, reducing the burden.
Secondly, the maintenance is higher. If the business needs no longer need to perform authentication operations,gin
Just delete itUse
method call, andnet/http
It needs to be allhandler
The decorative operation is processed, and the authentication operation node in the decorator node is deleted, which is relative to the workload ofgin
Very large and easy to make mistakes.
at last,gin
In scenarios where different middleware is required to handle requests for different parts, it is more flexible and simpler to implement. For example, some requests require authentication operations, some requests require error processing, and some require both error processing and authentication operations. In this scenario, you only need to passgin
Create three routing groupsrouter
, and then different routing groups are called separatelyUse
The method enables different middleware to realize the requirements, which is relative tonet/http
More flexible and maintainable.
This is why there isnet/http
On the premise ofgin
One of the important reasons for the framework.
4. Data binding
When processing HTTP requests, a common function is to automatically bind the data in the request to the structure. The following is a form data as an example, if usingnet/http
, how to bind data to a structure:
package main import ( "fmt" "log" "net/http" ) type User struct { Name string `json:"name"` Email string `json:"email"` } func handleFormSubmit(w , r *) { var user User // Bind form data to User structure = ("name") = ("email") // Process user data (w, "User created:%s (%s)", , ) } func main() { ("/createUser", handleFormSubmit) (":8080", nil) }
We need to callFormValue
Method, you have to read out the data from the form one by one and then set it into the structure. Moreover, when there are many fields, we are likely to miss some of them, resulting in problems with the subsequent processing logic. Moreover, we need to manually read the settings for each field, which also affects our development efficiency.
Let's take a look belowGin
How to read form data and set it into the structure:
package main import ( "fmt" "/gin-gonic/gin" ) type User struct { Name string `json:"name"` Email string `json:"email"` } func handleFormSubmit(c *) { var user User // Bind form data to User structure err := (&user) if err != nil { (, {"error": "Invalid form data"}) return } // Process user data (, {"message": ("User created:%s (%s)", , )}) } func main() { router := () ("/createUser", handleFormSubmit) (":8080") }
Look at line 17 of the above sample code and you can see the direct callShouldBind
Functions can automatically map the form data to the structure automatically, no longer need to read fields one by one, and then set them to the structure separately.
Compared to usingnet/http
, gin
Framework is more convenient in terms of data binding, and it is not prone to errors.gin
Variousapi
, Can map various types of data into structures, users only need to call the correspondingapi
Just do it. andnet/http
The corresponding operation is not provided, and the user needs to read the data and then manually set it into the structure.
5. Summary
In Go,net/http
Basic HTTP functionality is provided, but it is designed to be simple and versatile, rather than providing advanced features and convenient development experiences. When handling HTTP requests and building web applications, it will seem unscrupulous when handling complex routing rules; at the same time, it is difficult to achieve pluggable design for some public operations, such as logging, error processing, etc.; if you want to bind the request data to the structure,net/http
There are no simple operations provided, they all need to be implemented manually by users.
This is why it appears likeGin
Such a third-party library is built onnet/http
On top of it, it aims to simplify and accelerate the development of web applications.
Overall,Gin
It can help developers build web applications more efficiently, providing a better development experience and richer functions. Of course, choose to usenet/http
Or Gin depends on the size, needs and personal preferences of the project. For simple small projects,net/http
It may be enough, but for complex applications, Gin may be more suitable.
This is the end of this article about a brief analysis of the necessity of the Gin framework in Golang. For more related Golang Gin content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!