Skip to main content

Echo Query Parameters

Introduction

When building web applications with the Echo framework, you'll often need to extract and process data from URL query parameters. Query parameters are key-value pairs that appear after a question mark (?) in a URL, such as https://example.com/search?query=golang&page=2. They provide a way for clients to send data to your server without using a request body.

In this guide, you'll learn:

  • What query parameters are and how they work
  • How to access query parameters in Echo
  • Different methods for handling query parameters
  • Real-world examples and best practices

Understanding Query Parameters

Query parameters are a standard way to pass information through a URL. They follow a specific format:

  1. The parameters begin with a question mark (?)
  2. Each parameter is a key-value pair formatted as key=value
  3. Multiple parameters are separated by an ampersand (&)

For example:

https://api.example.com/products?category=electronics&sort=price_asc&limit=20

In this URL, we have three query parameters:

  • category with value electronics
  • sort with value price_asc
  • limit with value 20

Accessing Query Parameters in Echo

Echo makes it easy to access query parameters through its Context object. Let's look at the main methods:

Using c.QueryParam()

The most straightforward way to retrieve a query parameter is to use the QueryParam() method:

go
// Handler function
func getProducts(c echo.Context) error {
// Get query parameters
category := c.QueryParam("category")
sort := c.QueryParam("sort")

// Use the values
return c.String(http.StatusOK, fmt.Sprintf("Category: %s, Sort: %s", category, sort))
}

When a request is made to /products?category=electronics&sort=price_asc, this handler would respond with:

Category: electronics, Sort: price_asc

Using c.QueryParams()

If you need to access all query parameters at once, Echo provides the QueryParams() method that returns a map of parameter names to values:

go
func getAllParams(c echo.Context) error {
// Get all query parameters
params := c.QueryParams()

// Build a response
var response strings.Builder
for key, values := range params {
for _, value := range values {
response.WriteString(fmt.Sprintf("%s: %s\n", key, value))
}
}

return c.String(http.StatusOK, response.String())
}

For a request to /search?term=golang&category=programming&category=language, this would respond with:

term: golang
category: programming
category: language

Handling Multiple Values

Note that query parameters can have multiple values with the same key. For example, /search?tag=go&tag=web has two values for the tag parameter. To access all values for a specific parameter, use c.QueryParams().Get(key):

go
func getTags(c echo.Context) error {
// Get all values for the "tag" parameter
tags := c.QueryParams()["tag"]

return c.JSON(http.StatusOK, map[string]interface{}{
"tags": tags,
})
}

Type Conversion

Query parameters are always received as strings. If you need them in other types, you'll need to convert them:

go
func getProductsWithPagination(c echo.Context) error {
// Get query parameters
pageStr := c.QueryParam("page")
limitStr := c.QueryParam("limit")

// Convert to integers with default values
page := 1
limit := 10

if pageStr != "" {
if pageVal, err := strconv.Atoi(pageStr); err == nil && pageVal > 0 {
page = pageVal
}
}

if limitStr != "" {
if limitVal, err := strconv.Atoi(limitStr); err == nil && limitVal > 0 {
limit = limitVal
}
}

return c.JSON(http.StatusOK, map[string]interface{}{
"page": page,
"limit": limit,
"offset": (page - 1) * limit,
})
}

Validating Query Parameters

It's important to validate query parameters to ensure the data meets your requirements. Here's a simple example of validating a sorting parameter:

go
func getProductsWithSorting(c echo.Context) error {
// Get and validate the sort parameter
sort := c.QueryParam("sort")

// Validate sort parameter
validSortOptions := map[string]bool{
"price_asc": true,
"price_desc": true,
"name_asc": true,
"name_desc": true,
}

if sort != "" && !validSortOptions[sort] {
return c.JSON(http.StatusBadRequest, map[string]string{
"error": "Invalid sort parameter. Valid options are: price_asc, price_desc, name_asc, name_desc",
})
}

// Default sort if not provided
if sort == "" {
sort = "name_asc"
}

return c.JSON(http.StatusOK, map[string]string{
"sorting": sort,
})
}

Real-World Example: Product Search API

Let's build a more comprehensive example of a product search API that uses multiple query parameters:

go
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Category string `json:"category"`
Price float64 `json:"price"`
}

// Sample product database
var products = []Product{
{1, "Laptop", "electronics", 999.99},
{2, "Smartphone", "electronics", 599.99},
{3, "Coffee Maker", "kitchen", 89.99},
{4, "Running Shoes", "sports", 129.99},
{5, "Wireless Earbuds", "electronics", 149.99},
}

func searchProducts(c echo.Context) error {
// Get query parameters
category := c.QueryParam("category")
minPriceStr := c.QueryParam("min_price")
maxPriceStr := c.QueryParam("max_price")

// Parse price filters
var minPrice, maxPrice float64
var err error

if minPriceStr != "" {
minPrice, err = strconv.ParseFloat(minPriceStr, 64)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{
"error": "Invalid min_price parameter",
})
}
}

if maxPriceStr != "" {
maxPrice, err = strconv.ParseFloat(maxPriceStr, 64)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{
"error": "Invalid max_price parameter",
})
}
}

// Filter products based on parameters
filteredProducts := []Product{}

for _, product := range products {
// Filter by category if specified
if category != "" && product.Category != category {
continue
}

// Filter by min price if specified
if minPriceStr != "" && product.Price < minPrice {
continue
}

// Filter by max price if specified
if maxPriceStr != "" && product.Price > maxPrice {
continue
}

// Product passed all filters, add it to results
filteredProducts = append(filteredProducts, product)
}

return c.JSON(http.StatusOK, map[string]interface{}{
"products": filteredProducts,
"count": len(filteredProducts),
"filters": map[string]interface{}{
"category": category,
"min_price": minPrice,
"max_price": maxPrice,
},
})
}

// Register route
func registerRoutes(e *echo.Echo) {
e.GET("/products", searchProducts)
}

When making a request to /products?category=electronics&min_price=200, you'll get only electronics products priced at $200 or higher.

Advanced Techniques: Query Parameter Binding

For more complex APIs, Echo provides a convenient way to bind query parameters to structs using the c.Bind() method:

go
type SearchParams struct {
Category string `query:"category"`
MinPrice float64 `query:"min_price"`
MaxPrice float64 `query:"max_price"`
Sort string `query:"sort" default:"name_asc"`
Page int `query:"page" default:"1"`
Limit int `query:"limit" default:"10"`
}

func searchProductsWithBinding(c echo.Context) error {
// Create and bind parameters
params := new(SearchParams)

if err := c.Bind(params); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{
"error": "Invalid parameters",
})
}

// Now you can use params.Category, params.MinPrice, etc.
// Apply filtering logic...

return c.JSON(http.StatusOK, map[string]interface{}{
"params": params,
// other response data
})
}

Best Practices

  1. Always validate query parameters: Don't assume users will send valid data.
  2. Provide default values: For optional parameters, define sensible defaults.
  3. Use appropriate data types: Convert string parameters to appropriate types (int, float, bool).
  4. Handle multiple values when appropriate (e.g., for filtering by multiple categories).
  5. Document your API parameters: Make it clear what parameters your API accepts.
  6. Use parameter binding for complex APIs with many parameters.

Summary

Query parameters provide a flexible way to pass data to your Echo web applications. In this guide, we've covered:

  • How to access individual and multiple query parameters
  • Converting parameter values to appropriate types
  • Validating parameters to ensure data integrity
  • Building real-world examples that use query parameters
  • Advanced techniques like parameter binding

By mastering query parameters, you can build flexible, user-friendly APIs that allow clients to customize their requests exactly as needed.

Exercises

  1. Build a simple weather API that accepts city and units query parameters (where units can be "metric" or "imperial").
  2. Create a blog post search endpoint that allows filtering by tags, category, and date range using query parameters.
  3. Implement a product filter using multiple values for the same parameter (e.g., color=red&color=blue).
  4. Use parameter binding to create a complex search API with pagination, sorting, and filtering options.

Additional Resources



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