Skip to main content

Echo Path Parameters

Introduction

When building web applications, you often need to handle dynamic parts in your URLs. For example, you might want to retrieve a specific user by ID, or fetch a product based on its slug. Echo, a high-performance and minimalist Go web framework, provides an elegant way to handle these dynamic segments through path parameters.

Path parameters are parts of the URL path that can vary and are used to capture values from the request URL. They are essential for creating RESTful APIs and dynamic web applications.

In this tutorial, we'll explore how to define, access, and work with path parameters in Echo to create flexible and dynamic routes.

Understanding Path Parameters

Path parameters in Echo are defined in route paths using a colon (:) followed by a parameter name. When a request matches the route pattern, Echo extracts the values from the URL and makes them available to your handler functions.

Basic Syntax

The basic syntax for defining a path parameter is:

go
// Define a route with a path parameter
e.GET("/users/:id", handleUser)

In this example, :id is a path parameter that will match any value in that position of the URL.

Defining Routes with Path Parameters

Let's look at some common patterns for defining routes with path parameters:

go
package main

import (
"net/http"

"github.com/labstack/echo/v4"
)

func main() {
e := echo.New()

// Basic path parameter
e.GET("/users/:id", getUserHandler)

// Multiple path parameters
e.GET("/products/:category/:id", getProductHandler)

// Optional path parameter (using a separate route)
e.GET("/posts", getAllPostsHandler)
e.GET("/posts/:id", getPostHandler)

e.Start(":8080")
}

func getUserHandler(c echo.Context) error {
// Handler implementation
return nil
}

func getProductHandler(c echo.Context) error {
// Handler implementation
return nil
}

func getAllPostsHandler(c echo.Context) error {
// Handler implementation
return nil
}

func getPostHandler(c echo.Context) error {
// Handler implementation
return nil
}

Accessing Path Parameters

To access the value of a path parameter, use the c.Param() method from the Echo context:

go
func getUserHandler(c echo.Context) error {
// Get the id path parameter
id := c.Param("id")

return c.String(http.StatusOK, "User ID: "+id)
}

Let's see a complete example:

go
package main

import (
"net/http"

"github.com/labstack/echo/v4"
)

func main() {
e := echo.New()

e.GET("/users/:id", func(c echo.Context) error {
// Extract the id parameter
id := c.Param("id")

// Use the id in your response
return c.String(http.StatusOK, "User ID: "+id)
})

e.Start(":8080")
}

When you send a request to /users/123, you'll receive a response:

User ID: 123

Working with Multiple Path Parameters

Routes can have multiple path parameters. Let's see how to handle them:

go
package main

import (
"fmt"
"net/http"

"github.com/labstack/echo/v4"
)

func main() {
e := echo.New()

e.GET("/api/:version/users/:id", func(c echo.Context) error {
// Extract path parameters
version := c.Param("version")
id := c.Param("id")

response := fmt.Sprintf("API Version: %s, User ID: %s", version, id)
return c.String(http.StatusOK, response)
})

e.Start(":8080")
}

If you request /api/v1/users/42, the response would be:

API Version: v1, User ID: 42

Parameter Validation and Type Conversion

Path parameters are always captured as strings. If you need a different type (like an integer), you'll need to convert it:

go
package main

import (
"net/http"
"strconv"

"github.com/labstack/echo/v4"
)

func main() {
e := echo.New()

e.GET("/users/:id", func(c echo.Context) error {
// Get the id as a string
idStr := c.Param("id")

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

// Use the numeric ID
return c.JSON(http.StatusOK, map[string]interface{}{
"user_id": id,
"type": "numeric",
})
})

e.Start(":8080")
}

Path Parameter vs Query Parameter

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

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

Here's a comparison example:

go
package main

import (
"fmt"
"net/http"

"github.com/labstack/echo/v4"
)

func main() {
e := echo.New()

// Path parameter example
e.GET("/users/:id", func(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, fmt.Sprintf("Path parameter - User ID: %s", id))
})

// Query parameter example
e.GET("/users", func(c echo.Context) error {
id := c.QueryParam("id")
return c.String(http.StatusOK, fmt.Sprintf("Query parameter - User ID: %s", id))
})

e.Start(":8080")
}
  • Request to /users/42 will respond with: "Path parameter - User ID: 42"
  • Request to /users?id=42 will respond with: "Query parameter - User ID: 42"

Real-World Example: RESTful API

Let's build a simple RESTful API for a blog using path parameters:

go
package main

import (
"fmt"
"net/http"
"strconv"

"github.com/labstack/echo/v4"
)

// Post represents a blog post
type Post struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
Author string `json:"author"`
}

// Simple in-memory database
var posts = []Post{
{ID: 1, Title: "Introduction to Echo", Content: "Echo is a high performance web framework", Author: "John"},
{ID: 2, Title: "Go Concurrency", Content: "Goroutines and channels make concurrency easy", Author: "Jane"},
{ID: 3, Title: "Web Development with Go", Content: "Go is great for web servers", Author: "Bob"},
}

func main() {
e := echo.New()

// Get all posts
e.GET("/posts", func(c echo.Context) error {
return c.JSON(http.StatusOK, posts)
})

// Get a specific post by ID
e.GET("/posts/:id", func(c echo.Context) error {
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)

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

// Find the post by ID
for _, post := range posts {
if post.ID == id {
return c.JSON(http.StatusOK, post)
}
}

return c.JSON(http.StatusNotFound, map[string]string{
"error": "Post not found",
})
})

// Get posts by author
e.GET("/authors/:name/posts", func(c echo.Context) error {
authorName := c.Param("name")
var authorPosts []Post

for _, post := range posts {
if post.Author == authorName {
authorPosts = append(authorPosts, post)
}
}

if len(authorPosts) == 0 {
return c.JSON(http.StatusNotFound, map[string]string{
"error": fmt.Sprintf("No posts found for author '%s'", authorName),
})
}

return c.JSON(http.StatusOK, authorPosts)
})

e.Start(":8080")
}

With this API:

  • Request to /posts returns all posts
  • Request to /posts/1 returns the post with ID 1
  • Request to /authors/Jane/posts returns all posts by Jane

Advanced Patterns with Path Parameters

Echo supports some advanced patterns for path parameters:

Catch-All Parameters

You can use * to create a catch-all parameter that matches all characters, including slashes:

go
e.GET("/files/*filepath", func(c echo.Context) error {
filepath := c.Param("filepath")
return c.String(http.StatusOK, "You requested file: "+filepath)
})

A request to /files/docs/user-manual.pdf would capture docs/user-manual.pdf as the filepath parameter.

Custom Path Matching with Regular Expressions

Echo doesn't directly support regular expressions in route definitions. If you need more control over path parameter validation, you can:

  1. Define the route with standard parameters
  2. Perform validation in your handler function
go
e.GET("/users/:id", func(c echo.Context) error {
id := c.Param("id")

// Validate that id contains only digits
for _, char := range id {
if char < '0' || char > '9' {
return c.JSON(http.StatusBadRequest, map[string]string{
"error": "ID must contain only digits",
})
}
}

return c.String(http.StatusOK, "Valid user ID: "+id)
})

Summary

Path parameters are a powerful feature in Echo that enable you to build dynamic and flexible routes:

  • They're defined using a colon syntax (:paramName) in route paths
  • You access parameter values with c.Param("paramName")
  • Path parameters are always strings; convert them to appropriate types as needed
  • You can use multiple path parameters in a single route
  • The catch-all syntax (*paramName) captures the remaining path, including slashes

By mastering path parameters, you can create clean, RESTful APIs and dynamic web applications that handle various URL patterns effectively.

Additional Resources and Exercises

Further Learning

Exercises

  1. Basic Parameter Exercise:
    Create a route that handles /greet/:name and responds with "Hello, {name}!"

  2. Multiple Parameters:
    Build a calculator API with routes like /calculate/:operation/:num1/:num2 that performs the specified operation on the two numbers.

  3. Blog API Extension:
    Extend the blog API example with these features:

    • Get posts by category: /posts/category/:category
    • Filter posts by date range: /posts/from/:startDate/to/:endDate
    • Search posts: /posts/search/:query
  4. File Browser API:
    Create an API that uses catch-all parameters to simulate a file browser, where /files/*path returns information about the requested file path.

  5. URL Shortener Service:
    Build a simple URL shortener where /:shortCode redirects to the original URL stored in your database.

Remember, practice is key to mastering path parameters and web routing concepts!



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