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.
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:
{
"message": "Hello, john!"
}
Change the URL to http://localhost:8080/user/sarah
and you'll get:
{
"message": "Hello, sarah!"
}
Multiple URL Parameters
You can include multiple parameters in a single route pattern:
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:
{
"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:
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:
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:
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:
{
"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:
// 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:
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:
- Creating grouped routes with shared path prefixes
- Using URL parameters to fetch specific resources
- Proper error handling when parameters are invalid
- 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
- Use for resource identification: URL parameters work best for identifying specific resources (like IDs)
- Keep it simple: Avoid overly complex URL structures with too many parameters
- Validate all parameters: Always validate and sanitize user input
- Use meaningful names: Parameter names should clearly indicate what they represent
- 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:
- Create a route that accepts a username and returns different responses based on whether the username is an admin or regular user
- Build a route that handles product categories and subcategories using multiple URL parameters
- Implement a file server that uses a catch-all parameter to serve files from different directories
- 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! :)