Routing
Routing is one of the core features that all modern frameworks provide. Any web page or an API end point is accessed by a URL. Frameworks use routes to handle requests to these URLs. If a URL is http://www.example.com/some/random/route
, the route will be /some/random/route
.
Gin offers a fast router that's easy to configure and use. Apart from handling specified URLs, Gin routers can also handle patterns and grouped URLs.
In our application, we will:
Serve the index page at route
/
(HTTP GET request),Group user-related routes under the
/u
route,- Serve the login page at
/u/login
(HTTP GET request), - Process the login credentials at
/u/login
(HTTP POST request), - Log out at
/u/logout
(HTTP GET request), - Serve the registration page at
/u/register
(HTTP GET request), - Process the registration information at
/u/register
(HTTP POST request) ,
- Serve the login page at
Group article related routes under the
/article
route,- Serve the article creation page at
/article/create
(HTTP GET request), - Process the submitted article at
/article/create
(HTTP POST request), and - Serve the article page at
/article/view/:article_id
(HTTP GET request). Take note of the:article_id
part in this route. The:
at the beginning indicates that this is a dynamic route. This means that:article_id
can contain any value and Gin will make this value available in the route handler.
- Serve the article creation page at
Rendering
A web application can render a response in various formats like HTML, text, JSON, XML or other formats. API endpoints and microservices typically respond with data, commonly in JSON format but also in any other desired format.
In the next section, we'll see how we can render different types of responses without duplicating any functionality. We will primarily respond to a request with an HTML template. However, we will also define two end points which can respond with JSON or XML data.
Middleware
In the context of a Go web application, middleware is a piece of code that can be executed at any stage while handling an HTTP request. It is typically used to encapsulate common functionality that you want to apply to multiple routes. We can use middleware before and/or after an HTTP request is handled. Some common uses of middleware include authorization, validation, etc.
If middleware is used before a request is handled, any changes it makes to the request will be available in the main route handler. This is handy if we want to implement some validations on certain requests. On the other hand, if middleware is used after the route handler, it will have the response from the route handler. This can be used to modify the response from the route handler.
Gin allows us to write middleware that implements some common functionality that needs to be shared while handling multiple routes. This keeps the codebase small, separates concerns and improves code maintainability.
We want to ensure that some pages and actions, eg. creating an article, logging out, are available only to users who are logged in. We also want to ensure that some pages and actions, eg. registering, logging in, are available only to users who aren't logged in.
If we were to put this logic in every route, it would be quite tedious, repetitive and error-prone. Luckily, we can create middleware for each of these tasks and reuse them in specific routes.
We will also create middleware that will be applied to all routes. This middleware (setUserStatus
) will check whether a request is from an authenticated user or not. It will then set a flag that can be used in templates to modify the visibility of some of the menu links based on this flag.