Skip to main content

Method Override Middleware

Method override middleware that allows HTML forms to simulate PUT, PATCH, and DELETE requests using a hidden form field.

Installation

npm i remix

Function

methodOverride()

Creates middleware that overrides context.method with the value of the method override field. Signature:
function methodOverride(options?: MethodOverrideOptions): Middleware
Parameters:
  • options - Optional method override settings
Returns: A middleware that overrides context.method with the value of the method override field.
This middleware must be placed after the formData middleware in the middleware chain, or some other middleware that provides context.get(FormData).

Options

MethodOverrideOptions

interface MethodOverrideOptions {
  fieldName?: string
}

fieldName

The name of the form field to check for request method override.
  • Type: string
  • Default: '_method'

Basic Usage

import { createRouter } from 'remix/fetch-router'
import { formData } from 'remix/form-data-middleware'
import { methodOverride } from 'remix/method-override-middleware'

let router = createRouter({
  // methodOverride must come AFTER formData middleware
  middleware: [formData(), methodOverride()],
})

router.delete('/users/:id', async (context) => {
  let userId = context.params.id
  // Delete user logic...
  return new Response('User deleted')
})
HTML Form:
<form method="POST" action="/users/123">
  <input type="hidden" name="_method" value="DELETE" />
  <button type="submit">Delete User</button>
</form>

Custom Field Name

import { createRouter } from 'remix/fetch-router'
import { formData } from 'remix/form-data-middleware'
import { methodOverride } from 'remix/method-override-middleware'

let router = createRouter({
  middleware: [formData(), methodOverride({ fieldName: '__method__' })],
})
HTML Form:
<form method="POST" action="/users/123">
  <input type="hidden" name="__method__" value="PUT" />
  <button type="submit">Update User</button>
</form>

RESTful CRUD Example

import { createRouter } from 'remix/fetch-router'
import { formData } from 'remix/form-data-middleware'
import { methodOverride } from 'remix/method-override-middleware'

let router = createRouter({
  middleware: [formData(), methodOverride()],
})

// Create
router.post('/posts', async (context) => {
  let data = context.get(FormData)
  let title = data.get('title')
  let content = data.get('content')
  // Create post...
  return new Response('Post created', { status: 201 })
})

// Update
router.put('/posts/:id', async (context) => {
  let postId = context.params.id
  let data = context.get(FormData)
  // Update post...
  return new Response('Post updated')
})

// Partial update
router.patch('/posts/:id', async (context) => {
  let postId = context.params.id
  let data = context.get(FormData)
  // Partially update post...
  return new Response('Post updated')
})

// Delete
router.delete('/posts/:id', async (context) => {
  let postId = context.params.id
  // Delete post...
  return new Response('Post deleted')
})
HTML Forms:
<!-- Update form -->
<form method="POST" action="/posts/123">
  <input type="hidden" name="_method" value="PUT" />
  <input type="text" name="title" value="My Post" />
  <textarea name="content">Post content here</textarea>
  <button type="submit">Update Post</button>
</form>

<!-- Delete form -->
<form method="POST" action="/posts/123">
  <input type="hidden" name="_method" value="DELETE" />
  <button type="submit">Delete Post</button>
</form>

How It Works

  1. Browser submits a POST request with the form data
  2. formData middleware parses the form data
  3. methodOverride middleware reads the _method field value
  4. If the value is a valid HTTP method (GET, POST, PUT, PATCH, DELETE, etc.), it overrides context.method
  5. Router matches the request to the appropriate handler based on the overridden method

Supported Methods

The middleware supports all standard HTTP methods:
  • GET
  • POST
  • PUT
  • PATCH
  • DELETE
  • HEAD
  • OPTIONS

Build docs developers (and LLMs) love