Last active
March 26, 2024 13:47
-
-
Save yusukebe/180bfcf261d142df4e233e90e65cb63b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type MethodOverrideOptions = { | |
// Default is 'form' and the value is `_method` | |
form?: string | |
header?: string | |
query?: string | |
} | |
const DEFAULT_METHOD_FORM_NAME = '_method' | |
const methodOverride = (options?: MethodOverrideOptions): MiddlewareHandler => | |
async function methodOverride(c, next) { | |
// Method override by form | |
if (!options || options.form || !(options.form || options.header || options.query)) { | |
const methodFormName = options?.form || DEFAULT_METHOD_FORM_NAME | |
const contentType = c.req.header('content-type') | |
if (!(contentType === 'multipart/form-data' || contentType === 'application/x-www-form-urlencoded')) { | |
return await next() | |
} | |
const clonedRequest = c.req.raw.clone() | |
const newRequest = clonedRequest.clone() | |
const form = await clonedRequest.formData() | |
const method = form.get(methodFormName) | |
if (method) { | |
const newForm = await newRequest.formData() | |
newForm.delete(methodFormName) | |
const newHeaders = new Headers(clonedRequest.headers) | |
newHeaders.delete('content-type') | |
newHeaders.delete('content-length') | |
const request = new Request(c.req.url, { | |
body: newForm, | |
headers: newHeaders, | |
method | |
}) | |
return app.fetch(request, c.env, c.executionCtx) | |
} | |
} | |
// Method override by header | |
else if (options.header) { | |
const headerName = options.header | |
const method = c.req.header(headerName) | |
if (method) { | |
const newHeaders = new Headers(c.req.raw.headers) | |
newHeaders.delete(headerName) | |
const request = new Request(c.req.raw, { | |
headers: newHeaders, | |
method | |
}) | |
return app.fetch(request, c.env, c.executionCtx) | |
} | |
} | |
// Method override by query | |
else if (options.query) { | |
const queryName = options.query | |
const method = c.req.query(queryName) | |
if (method) { | |
const url = new URL(c.req.url) | |
url.searchParams.delete(queryName) | |
const request = new Request(url.toString(), { | |
body: c.req.raw.body, | |
headers: c.req.raw.headers, | |
method | |
}) | |
return app.fetch(request, c.env, c.executionCtx) | |
} | |
} | |
await next() | |
} |
Either way, I would like this feature and would like to make a PR.
Thanks for the explanation about the content-type, I understand. Thanks!
Created the PR! honojs/hono#2420
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks @usualoma !
That's right! I'll implement it as you said. For my use case, it's not a problem; it does not override on GET.
I am removing the
content-type
header because if its value is startingmultipart/form-data
, the form content will not be created properly without removing it.However, if we create a Request with a new FormData instance in the body, the new
content-type
is automatically added.The following line needs to be modified, but if the
content-type
starts withmultipart/form-data
, we may remove it.