Skip to main content

Echo Method Override

Introduction

In modern web development, RESTful APIs commonly use different HTTP methods (GET, POST, PUT, DELETE, etc.) to perform different operations on resources. However, not all clients support the full range of HTTP methods. For example, HTML forms traditionally only support GET and POST methods, and some older proxies might not handle methods like PUT or DELETE correctly.

Method Override is a technique that allows clients to use a supported method (typically POST) while indicating that the server should treat the request as if it were a different method. Echo framework provides built-in support for this pattern through its method override middleware.

Why Use Method Override?

Method override is particularly useful when:

  1. Working with HTML forms that only support GET and POST
  2. Supporting clients behind restrictive firewalls or proxies
  3. Building APIs that need to be accessible to a wide range of clients
  4. Testing RESTful APIs with tools that have limited HTTP method support

Using Method Override in Echo

Echo provides several ways to override the HTTP method:

1. Using the _method Query Parameter

go
e := echo.New()
e.Pre(middleware.MethodOverride())

// Now clients can make requests like POST /users?_method=DELETE

2. Using a Form Field

go
e := echo.New()
e.Pre(middleware.MethodOverride())

// HTML form can include <input type="hidden" name="_method" value="DELETE">

3. Using a Custom HTTP Header

go
e := echo.New()
e.Pre(middleware.MethodOverrideWithConfig(middleware.MethodOverrideConfig{
Getter: middleware.MethodFromHeader("X-HTTP-Method-Override"),
}))

// Clients can set header: X-HTTP-Method-Override: DELETE

Basic Method Override Example

Let's see a complete example of setting up method override in an Echo application:

go
package main

import (
"net/http"

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

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

// Add method override middleware
e.Pre(middleware.MethodOverride())

// Define routes for different HTTP methods
e.GET("/users/:id", getUser)
e.PUT("/users/:id", updateUser)
e.DELETE("/users/:id", deleteUser)

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

func getUser(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, "Getting user "+id)
}

func updateUser(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, "Updating user "+id)
}

func deleteUser(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, "Deleting user "+id)
}

HTML Form Method Override Example

Here's an example of an HTML form that uses method override to perform a DELETE operation:

html
<form action="/users/123" method="POST">
<input type="hidden" name="_method" value="DELETE">
<button type="submit">Delete User</button>
</form>

When this form is submitted, Echo will interpret the request as a DELETE request to /users/123 instead of a POST request.

Advanced Configuration

You can customize the method override behavior using the configuration options:

go
e.Pre(middleware.MethodOverrideWithConfig(middleware.MethodOverrideConfig{
// Override method if the path contains this prefix
Skipper: func(c echo.Context) bool {
return !strings.HasPrefix(c.Path(), "/api")
},
// Define the query param name (default is "_method")
Getter: middleware.MethodFromForm("_method"),
}))

Real-world Example: RESTful Article Management API

Let's build a simple article management API with full CRUD operations that supports method override:

go
package main

import (
"net/http"

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

type Article struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
}

var articles = []Article{
{ID: 1, Title: "Introduction to Echo", Content: "Echo is a high performance web framework."},
{ID: 2, Title: "Method Override in Echo", Content: "Method override allows clients to use different HTTP methods."},
}

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

// Add method override middleware
e.Pre(middleware.MethodOverride())

// Add logging to see which method is actually being used
e.Use(middleware.Logger())

// Define RESTful routes
e.GET("/articles", getArticles)
e.GET("/articles/:id", getArticle)
e.POST("/articles", createArticle)
e.PUT("/articles/:id", updateArticle)
e.DELETE("/articles/:id", deleteArticle)

// Serve HTML form for testing method override
e.GET("/form", func(c echo.Context) error {
html := `
<html>
<body>
<h3>Test DELETE using Method Override</h3>
<form action="/articles/1" method="POST">
<input type="hidden" name="_method" value="DELETE">
<button type="submit">Delete Article #1</button>
</form>

<h3>Test PUT using Method Override</h3>
<form action="/articles/2" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="text" name="title" value="Updated Title">
<input type="text" name="content" value="Updated Content">
<button type="submit">Update Article #2</button>
</form>
</body>
</html>
`
return c.HTML(http.StatusOK, html)
})

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

func getArticles(c echo.Context) error {
return c.JSON(http.StatusOK, articles)
}

func getArticle(c echo.Context) error {
id := c.Param("id")
// Implementation details omitted
return c.String(http.StatusOK, "Getting article "+id)
}

func createArticle(c echo.Context) error {
// Implementation details omitted
return c.String(http.StatusCreated, "Article created")
}

func updateArticle(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, "Updating article "+id+" with method: "+c.Request().Method)
}

func deleteArticle(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, "Deleting article "+id+" with method: "+c.Request().Method)
}

This example provides an API for article management and also serves an HTML form at /form where you can test the method override feature directly in your browser.

Testing Method Override with cURL

You can test method override using cURL:

bash
# Using query parameter
curl -X POST "http://localhost:8080/articles/1?_method=DELETE"

# Using form data
curl -X POST -d "_method=PUT" -d "title=New Title" http://localhost:8080/articles/1

# Using custom header
curl -X POST -H "X-HTTP-Method-Override: DELETE" http://localhost:8080/articles/1

Best Practices

  1. Use method override only when necessary - It's a workaround for clients with limitations, not a replacement for proper HTTP method usage.

  2. Consider security implications - Method override can potentially expose your API to unintended operations if not properly secured.

  3. Document your API clearly - Make sure clients know how to use method override if your API requires it.

  4. Use appropriate status codes - Even when using method override, return appropriate HTTP status codes for each operation.

  5. Test thoroughly - Ensure that all your routes work correctly with both direct methods and overridden methods.

Summary

Method override in Echo is a powerful feature that lets you build RESTful APIs that can be accessed by clients with limited HTTP method support. By implementing method override, you can:

  • Support HTML forms that need to perform PUT, DELETE, and other operations
  • Make your APIs accessible to a wider range of clients
  • Maintain RESTful design principles even when working with limited clients

Echo provides flexible configuration options through its middleware system, allowing you to customize how method override works in your application.

Additional Resources

Exercises

  1. Create an Echo application that serves a user management API with GET, POST, PUT, and DELETE operations, and provide an HTML form to test method override.

  2. Implement method override using a custom header in an Echo application.

  3. Build a blog API that supports all CRUD operations and can be accessed through HTML forms using method override.

  4. Create a middleware that logs when a method has been overridden, showing both the original and the new method.



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