Skip to main content

Echo Redirect Response

Introduction

When building web applications, you often need to redirect users from one URL to another. This might happen after a form submission, after authentication, or when resources have moved. The Echo framework provides a simple and efficient way to handle these redirects through its Redirect Response functionality.

In this tutorial, we'll explore how Echo handles redirects, the different types of redirects you can implement, and best practices for using them effectively in your applications.

Understanding HTTP Redirects

Before diving into Echo's implementation, it's important to understand what HTTP redirects are. A redirect is a server response that tells the client (usually a web browser) to make a new request to a different URL. Redirects are indicated by HTTP status codes in the 3xx range:

  • 301 - Moved Permanently
  • 302 - Found (commonly used for temporary redirects)
  • 303 - See Other (typically used after POST requests)
  • 307 - Temporary Redirect
  • 308 - Permanent Redirect

Basic Redirect in Echo

Echo makes implementing redirects straightforward. The most common way to redirect in Echo is using the Redirect method of the Context object:

go
func handleRedirect(c echo.Context) error {
return c.Redirect(http.StatusFound, "/new-page")
}

This code will send a 302 Found response to the client, instructing it to navigate to "/new-page".

Redirect Types in Echo

Temporary vs. Permanent Redirects

Echo allows you to specify different types of redirects by changing the status code:

go
// Temporary redirect (302 Found)
return c.Redirect(http.StatusFound, "/temporary-location")

// Permanent redirect (301 Moved Permanently)
return c.Redirect(http.StatusMovedPermanently, "/new-permanent-location")

When to use each:

  • Use temporary redirects (302, 307) when the original URL might be used again in the future
  • Use permanent redirects (301, 308) when the resource has moved permanently and you want search engines to update their indexes

Redirect After Form Submission (POST/Redirect/GET Pattern)

A common pattern in web development is redirecting after a form submission to prevent duplicate submissions when users refresh the page:

go
func handleFormSubmission(c echo.Context) error {
// Process form submission
name := c.FormValue("name")

// Save data to database
err := saveToDatabase(name)
if err != nil {
return err
}

// Redirect to a success page (303 See Other)
return c.Redirect(http.StatusSeeOther, "/submission-success")
}

Using http.StatusSeeOther (303) is particularly appropriate after POST requests as it explicitly tells the client to use GET for the new request.

Redirecting with Dynamic URLs

Often you need to redirect to URLs constructed dynamically based on user input or application state:

go
func redirectToProfile(c echo.Context) error {
// Get user ID from the request
userID := c.Param("id")

// Build the target URL
targetURL := fmt.Sprintf("/users/%s/profile", userID)

// Redirect to the user's profile
return c.Redirect(http.StatusFound, targetURL)
}

Redirecting with Query Parameters

You can include query parameters in your redirect URLs to pass information to the target page:

go
func redirectWithQuery(c echo.Context) error {
// Build URL with query parameters
targetURL := "/search?keyword=echo&page=1"

return c.Redirect(http.StatusFound, targetURL)
}

For more complex query parameters, you can use the url package to build URLs properly:

go
func redirectWithComplexQuery(c echo.Context) error {
baseURL := "/search"

// Create URL with proper encoding of query parameters
u, err := url.Parse(baseURL)
if err != nil {
return err
}

q := u.Query()
q.Set("keyword", "web development")
q.Set("category", "programming")
q.Set("level", "beginner")
u.RawQuery = q.Encode()

return c.Redirect(http.StatusFound, u.String())
}

Practical Examples

1. Authentication Redirect

A common use case is redirecting unauthenticated users to a login page:

go
func protectedHandler(c echo.Context) error {
// Check if user is authenticated
userID := getUserFromSession(c)
if userID == "" {
// Store the original URL they were trying to access
originalURL := c.Request().URL.String()
return c.Redirect(http.StatusFound, "/login?redirect=" + url.QueryEscape(originalURL))
}

// Continue with protected handler logic
return c.String(http.StatusOK, "Protected content")
}

2. API Version Redirect

If you've updated your API, you might want to redirect clients to the new endpoints:

go
func apiV1Handler(c echo.Context) error {
// Redirect to the new API version
resource := c.Param("resource")
return c.Redirect(http.StatusMovedPermanently, "/api/v2/" + resource)
}

3. URL Shortener

A simple URL shortener application might use redirects as its core functionality:

go
func handleShortURL(c echo.Context) error {
// Get the short code from the URL
code := c.Param("code")

// Look up the original URL from the database
originalURL, err := lookupURL(code)
if err != nil {
return c.String(http.StatusNotFound, "Short URL not found")
}

// Redirect to the original URL
return c.Redirect(http.StatusMovedPermanently, originalURL)
}

Best Practices for Echo Redirects

  1. Use the appropriate status code for your use case:

    • 301 for permanent redirects
    • 302 for temporary redirects
    • 303 after form submissions (PRG pattern)
    • 307/308 for preserving the HTTP method
  2. Always validate and sanitize dynamic parts of redirect URLs to prevent open redirect vulnerabilities

  3. Use URL encoding for query parameters to ensure they're properly formatted

  4. Consider redirect loops - make sure your logic doesn't create infinite redirect cycles

  5. Use relative URLs when appropriate for better maintainability

Complete Example: Multi-step Form with Redirects

Here's a more complete example showing a multi-step form that uses redirects between steps:

go
package main

import (
"net/http"

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

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

// Form steps
e.GET("/form/step1", showStep1)
e.POST("/form/step1", processStep1)
e.GET("/form/step2", showStep2)
e.POST("/form/step2", processStep2)
e.GET("/form/complete", showComplete)

e.Logger.Fatal(e.Start(":8080"))
}

func showStep1(c echo.Context) error {
return c.HTML(http.StatusOK, `
<form method="POST">
<h1>Step 1</h1>
<input name="name" placeholder="Your name">
<button type="submit">Next</button>
</form>
`)
}

func processStep1(c echo.Context) error {
name := c.FormValue("name")

// In a real app, you'd store this in a session or database
// For simplicity, we'll pass it as a query parameter
return c.Redirect(http.StatusSeeOther, "/form/step2?name=" + url.QueryEscape(name))
}

func showStep2(c echo.Context) error {
name := c.QueryParam("name")

return c.HTML(http.StatusOK, `
<form method="POST">
<h1>Step 2</h1>
<p>Hello, ` + name + `!</p>
<input name="email" placeholder="Your email">
<input type="hidden" name="name" value="` + name + `">
<button type="submit">Complete</button>
</form>
`)
}

func processStep2(c echo.Context) error {
name := c.FormValue("name")
email := c.FormValue("email")

// Save the form data
// ...

return c.Redirect(http.StatusSeeOther, "/form/complete?name=" + url.QueryEscape(name))
}

func showComplete(c echo.Context) error {
name := c.QueryParam("name")

return c.HTML(http.StatusOK, `
<h1>Form Complete</h1>
<p>Thank you, ` + name + `!</p>
<a href="/form/step1">Start over</a>
`)
}

Common Gotchas and Solutions

1. Redirect URL Not Being Properly Encoded

Problem:

go
// Problematic code
return c.Redirect(http.StatusFound, "/search?term=" + searchTerm)

Solution:

go
// Properly encoded URL
return c.Redirect(http.StatusFound, "/search?term=" + url.QueryEscape(searchTerm))

2. Losing Form Data During Redirects

HTTP redirects don't carry request body data between requests.

Solution: Use sessions, temporary storage, or query parameters to pass data between redirects:

go
func processForm(c echo.Context) error {
data := c.FormValue("important_data")

// Store in session
session, _ := session.Get("session", c)
session.Values["form_data"] = data
session.Save(c.Request(), c.Response())

return c.Redirect(http.StatusSeeOther, "/next-page")
}

Summary

Echo Redirect Response provides a clean, simple way to implement HTTP redirects in your web applications. Key points to remember:

  • Use c.Redirect(statusCode, url) to implement redirects
  • Choose the appropriate status code for your use case (301, 302, 303, 307, 308)
  • Always encode dynamic parts of your URLs to avoid security issues
  • Use the POST/Redirect/GET pattern after form submissions
  • Consider redirect chains and possible loops in your application flow

With these tools and patterns at your disposal, you can create smooth, user-friendly navigation flows in your Echo-based web applications.

Additional Resources

Exercises

  1. Create a simple URL shortener that redirects short codes to full URLs
  2. Implement a login system that redirects users to their originally requested page after authentication
  3. Build a multi-step form that uses redirects between steps and preserves user input
  4. Create an API versioning system that uses 301 redirects to point clients to the newest API endpoints
  5. Implement a "smart redirect" that sends mobile users to a mobile-optimized version of your site


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