Skip to main content

Gin URL Parameters

URL parameters are a crucial part of building dynamic web applications. They allow you to create flexible routes that can handle different inputs without defining separate handlers for each variation. In this tutorial, we'll explore how to work with URL parameters in the Gin web framework.

What Are URL Parameters?

URL parameters (also called path parameters) are variable parts of a URL path. For example, in the URL /users/123, the 123 part could be a parameter that identifies a specific user. Rather than creating separate routes for each user ID, you can define a single route pattern with a parameter placeholder.

In Gin, URL parameters are defined in route patterns using the :paramName syntax.

Basic URL Parameters

Let's start with a basic example of defining and accessing URL parameters in Gin.

go
package main

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

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

// Route with a parameter
router.GET("/user/:name", func(c *gin.Context) {
// Access the parameter
name := c.Param("name")
c.JSON(http.StatusOK, gin.H{
"message": "Hello, " + name + "!",
})
})

router.Run(":8080")
}

In this example:

  • We define a route /user/:name where :name is a parameter
  • Inside the handler, we use c.Param("name") to extract the parameter value
  • The parameter value is then used in the response

Testing the Route

If you access http://localhost:8080/user/john in your browser or API client, you'll receive:

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

Change the URL to http://localhost:8080/user/sarah and you'll get:

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

Multiple URL Parameters

You can include multiple parameters in a single route pattern:

go
router.GET("/users/:userID/posts/:postID", func(c *gin.Context) {
userID := c.Param("userID")
postID := c.Param("postID")

c.JSON(http.StatusOK, gin.H{
"userID": userID,
"postID": postID,
})
})

With this setup, accessing http://localhost:8080/users/42/posts/123 would return:

json
{
"userID": "42",
"postID": "123"
}

Parameter Validation and Type Conversion

URL parameters are always extracted as strings. For proper development, you'll often need to validate and convert these values:

go
router.GET("/products/:id", func(c *gin.Context) {
idStr := c.Param("id")

// Convert string to int
id, err := strconv.Atoi(idStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Invalid product ID",
})
return
}

// Check if ID is in valid range
if id <= 0 {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Product ID must be positive",
})
return
}

// Process valid ID
c.JSON(http.StatusOK, gin.H{
"product_id": id,
"message": "Product found",
})
})

Don't forget to import the strconv package:

go
import "strconv"

Catch-All Parameters

Sometimes you need to match a part of the URL that may contain multiple path segments. Gin provides a catch-all parameter for this purpose using the *paramName syntax:

go
router.GET("/files/*filepath", func(c *gin.Context) {
filepath := c.Param("filepath")

// Note: filepath will include the leading slash
c.JSON(http.StatusOK, gin.H{
"filepath": filepath,
})
})

If you access http://localhost:8080/files/images/profile/avatar.png, you'll receive:

json
{
"filepath": "/images/profile/avatar.png"
}

Note that the catch-all parameter value includes the leading slash.

Optional Parameters

Gin doesn't directly support optional path parameters. However, you can achieve this behavior by defining multiple routes:

go
// Route with parameter
router.GET("/user/:name", userHandler)

// Route without parameter
router.GET("/user", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "User list",
})
})

// Handler function
func userHandler(c *gin.Context) {
name := c.Param("name")
c.JSON(http.StatusOK, gin.H{
"message": "Hello, " + name + "!",
})
}

Real-World Example: RESTful API

Let's build a simple RESTful API for managing a book collection using URL parameters:

go
package main

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

// Book represents book data
type Book struct {
ID int `json:"id"`
Title string `json:"title"`
Author string `json:"author"`
}

// Mock database
var books = []Book{
{ID: 1, Title: "The Go Programming Language", Author: "Alan Donovan & Brian Kernighan"},
{ID: 2, Title: "Clean Code", Author: "Robert C. Martin"},
{ID: 3, Title: "Designing Data-Intensive Applications", Author: "Martin Kleppmann"},
}

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

// Book routes
bookRoutes := router.Group("/books")
{
// Get all books
bookRoutes.GET("", getAllBooks)

// Get a specific book
bookRoutes.GET("/:id", getBookByID)

// Get books by an author
bookRoutes.GET("/author/:name", getBooksByAuthor)
}

router.Run(":8080")
}

func getAllBooks(c *gin.Context) {
c.JSON(http.StatusOK, books)
}

func getBookByID(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)

if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid book ID"})
return
}

for _, book := range books {
if book.ID == id {
c.JSON(http.StatusOK, book)
return
}
}

c.JSON(http.StatusNotFound, gin.H{"error": "Book not found"})
}

func getBooksByAuthor(c *gin.Context) {
authorName := c.Param("name")
var result []Book

for _, book := range books {
if book.Author == authorName {
result = append(result, book)
}
}

if len(result) == 0 {
c.JSON(http.StatusNotFound, gin.H{"error": "No books found for this author"})
return
}

c.JSON(http.StatusOK, result)
}

This example demonstrates:

  1. Creating grouped routes with shared path prefixes
  2. Using URL parameters to fetch specific resources
  3. Proper error handling when parameters are invalid
  4. Converting string parameters to the correct type

URL Parameters vs. Query Parameters

It's important to understand the difference between URL parameters and query parameters:

  • URL parameters are part of the path: /users/:id
  • Query parameters are appended to the URL after a question mark: /users?id=123

URL parameters are typically used for identifying a specific resource (like a user ID), while query parameters are better suited for filtering, sorting, or pagination.

Gin handles these differently:

  • URL parameters: c.Param("paramName")
  • Query parameters: c.Query("paramName") (covered in another tutorial)

Best Practices for URL Parameters

  1. Use for resource identification: URL parameters work best for identifying specific resources (like IDs)
  2. Keep it simple: Avoid overly complex URL structures with too many parameters
  3. Validate all parameters: Always validate and sanitize user input
  4. Use meaningful names: Parameter names should clearly indicate what they represent
  5. Document your routes: Keep clear documentation of what parameters each route expects

Summary

In this tutorial, you've learned:

  • How to define routes with URL parameters in Gin
  • How to extract parameter values using c.Param()
  • Working with multiple parameters in a single route
  • Using catch-all parameters for flexible matching
  • Validating and converting parameter values
  • Building RESTful APIs with URL parameters

URL parameters are a powerful way to make your web applications more dynamic and flexible. By mastering them, you can build cleaner APIs that follow RESTful conventions.

Exercises

To reinforce what you've learned, try these exercises:

  1. Create a route that accepts a username and returns different responses based on whether the username is an admin or regular user
  2. Build a route that handles product categories and subcategories using multiple URL parameters
  3. Implement a file server that uses a catch-all parameter to serve files from different directories
  4. Create a versioned API where the version is specified as a URL parameter

Additional Resources



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