Skip to main content

Gin Basic Routes

In web development, routing is the process of determining how an application responds to client requests to specific endpoints, which are URIs (or paths) and a specific HTTP request method (GET, POST, etc.). In this guide, we'll explore how to set up basic routes in the Gin framework, one of the most popular web frameworks for Go.

Introduction to Gin Routing

Gin makes it easy to define routes that respond to different HTTP methods and paths. A route is essentially a combination of:

  1. An HTTP method (GET, POST, PUT, DELETE, etc.)
  2. A URL path (e.g., /users, /products/:id)
  3. A handler function that executes when the route is matched

When a request comes in, Gin matches it against all defined routes and executes the appropriate handler function.

Setting Up a Basic Gin Application

Before we dive into routes, let's set up a basic Gin application:

go
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
// Create a default Gin router with Logger and Recovery middleware
router := gin.Default()

// Add your routes here

// Start the server on port 8080
router.Run(":8080")
}

Defining Basic Routes

Let's explore the fundamental ways to define routes in Gin:

Simple GET Route

The most basic route responds to GET requests at a specific path:

go
router.GET("/hello", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Hello, World!",
})
})

When you visit http://localhost:8080/hello in your browser, you'll see:

json
{
"message": "Hello, World!"
}

Routes for Different HTTP Methods

Gin provides convenient methods for all common HTTP verbs:

go
// GET method
router.GET("/users", getUsers)

// POST method
router.POST("/users", createUser)

// PUT method
router.PUT("/users/:id", updateUser)

// DELETE method
router.DELETE("/users/:id", deleteUser)

// PATCH method
router.PATCH("/users/:id", partiallyUpdateUser)

// OPTIONS method
router.OPTIONS("/users", optionsUser)

// HEAD method
router.HEAD("/users", headUser)

Let's implement some of these handlers:

go
func getUsers(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"users": []string{"John", "Jane", "Bob"},
})
}

func createUser(c *gin.Context) {
c.JSON(http.StatusCreated, gin.H{
"message": "User created successfully",
})
}

func updateUser(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"message": "User " + id + " updated successfully",
})
}

func deleteUser(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"message": "User " + id + " deleted successfully",
})
}

Using the Any Method

If you want a route to respond to all HTTP methods, you can use Any:

go
router.Any("/universal", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "I respond to any HTTP method",
"method": c.Request.Method,
})
})

NoRoute and NoMethod

You can also customize what happens when no route matches or when the route exists but the HTTP method is not allowed:

go
// Handle 404 not found
router.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{
"message": "Page not found",
})
})

// Handle 405 method not allowed
router.NoMethod(func(c *gin.Context) {
c.JSON(http.StatusMethodNotAllowed, gin.H{
"message": "Method not allowed",
})
})

Route Parameters

Routes often need to capture values from the URL. Gin makes this easy with route parameters:

Path Parameters

Path parameters are segments of the URL path that are variable and can be captured:

go
router.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"user_id": id,
"message": "User details retrieved",
})
})

If you visit http://localhost:8080/users/42, you'll see:

json
{
"message": "User details retrieved",
"user_id": "42"
}

Wildcard Parameters

You can also use wildcards to match multiple path segments:

go
router.GET("/files/*filepath", func(c *gin.Context) {
path := c.Param("filepath")
c.JSON(http.StatusOK, gin.H{
"filepath": path,
"message": "File path captured",
})
})

If you visit http://localhost:8080/files/documents/report.pdf, you'll see:

json
{
"filepath": "/documents/report.pdf",
"message": "File path captured"
}

Query Parameters

To access query parameters (e.g., ?name=john&age=25), use the Query method:

go
router.GET("/search", func(c *gin.Context) {
query := c.Query("q")
page := c.DefaultQuery("page", "1") // provides a default value if parameter is not present

c.JSON(http.StatusOK, gin.H{
"query": query,
"page": page,
"message": "Search results",
})
})

If you visit http://localhost:8080/search?q=golang&page=2, you'll see:

json
{
"message": "Search results",
"page": "2",
"query": "golang"
}

Grouping Routes

For larger applications, you might want to group related routes together:

go
// Create a group for API version 1
v1 := router.Group("/v1")
{
v1.GET("/users", getUsers)
v1.GET("/users/:id", getUserByID)
v1.POST("/users", createUser)
}

// Create a group for API version 2
v2 := router.Group("/v2")
{
v2.GET("/users", getUsersV2)
v2.GET("/users/:id", getUserByIDV2)
v2.POST("/users", createUserV2)
}

This makes your code more organized and easier to maintain, especially when you need to apply common middleware to a group of routes.

A Complete Example

Let's put everything together in a complete, real-world example:

go
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
router := gin.Default()

// Basic routes
router.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Welcome to our API",
})
})

// API group
api := router.Group("/api")
{
// Users resource
users := api.Group("/users")
{
users.GET("/", getUsers)
users.GET("/:id", getUserByID)
users.POST("/", createUser)
users.PUT("/:id", updateUser)
users.DELETE("/:id", deleteUser)
}

// Products resource
products := api.Group("/products")
{
products.GET("/", getProducts)
products.GET("/:id", getProductByID)
products.GET("/search", searchProducts)
}
}

// Static files
router.Static("/static", "./static")

// NoRoute handler
router.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{
"message": "Resource not found",
})
})

router.Run(":8080")
}

func getUsers(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"users": []string{"John", "Jane", "Bob"},
})
}

func getUserByID(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"id": id,
"name": "John Doe",
"email": "[email protected]",
})
}

func createUser(c *gin.Context) {
c.JSON(http.StatusCreated, gin.H{
"message": "User created successfully",
})
}

func updateUser(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"message": "User " + id + " updated successfully",
})
}

func deleteUser(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"message": "User " + id + " deleted successfully",
})
}

func getProducts(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"products": []string{"Laptop", "Phone", "Tablet"},
})
}

func getProductByID(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"id": id,
"name": "Laptop XYZ",
"price": 999.99,
})
}

func searchProducts(c *gin.Context) {
query := c.Query("q")
category := c.DefaultQuery("category", "all")

c.JSON(http.StatusOK, gin.H{
"query": query,
"category": category,
"results": []string{"Laptop XYZ", "Laptop ABC"},
})
}

Summary

In this guide, we've covered the basics of routing in the Gin framework:

  • Setting up a basic Gin application
  • Defining routes for different HTTP methods
  • Handling route parameters
  • Working with query parameters
  • Grouping related routes together
  • Creating a complete API structure

Understanding these concepts is fundamental to building web applications with Gin. As you become more comfortable with basic routing, you can explore more advanced features like middleware, custom validators, and authentication.

Further Resources and Exercises

Additional Resources

Exercises

  1. Basic API: Create a simple API for a todo list with endpoints for listing, creating, updating, and deleting tasks.

  2. Parameter Handling: Build a route that accepts multiple parameters and query strings, such as /products/:category/:id with optional query parameters for filtering.

  3. Route Groups: Create a REST API for a blog with separate route groups for posts, comments, and users.

  4. Error Handling: Improve the sample application by adding more robust error handling for different scenarios.

  5. Static Files: Add support for serving static files like CSS, JavaScript, and images for a simple website.

By practicing these exercises, you'll gain a deeper understanding of Gin's routing capabilities and become more proficient in developing web applications with Go.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)