Native HTML only supports sending GET and POST requests with forms to the server. However, utilizing Method Spoofing with AdonisJS we can spoof POST requests to the remainder of the Http Methods, ie: PUT, PATCH, and DELETE so that AdonisJS utilizes the spoofed method to match the desired route.
In essence, if we wanted to target a PUT: /posts
route, we can do so using Method Spoofing and a native HTML form.
Method Spoofing Requirements
In order to utilize Http Method Spoofing with AdonisJS a few conditions need to be met.
http.allowMethodSpoofing
within ourconfig/app.ts
file must betrue
. This is defaulted tofalse
within new projects.Our native HTML form must use
POST
as its method.The route's URL must contain the spoofed method in its query string.
Turning On Method Spoofing
The most important thing to note from above if you’re looking to use Method Spoofing is that you need to enable it within your AdonisJS project. To do so, open your config/app.ts
file and scroll down to the http
config. allowMethodSpoofing
should be one of the first properties under http
, just set its value to true
.
export const http: ServerConfig = { /* |-------------------------------------------------------------------------- | Allow method spoofing |-------------------------------------------------------------------------- | | Method spoofing enables defining custom HTTP methods using a query string | `_method`. This is usually required when you are making traditional | form requests and wants to use HTTP verbs like `PUT`, `DELETE` and | so on. | */ allowMethodSpoofing: true, // ... }
Copied!
Method Spoofing Query String
In order to specify what Http Method we want our request spoofed to, we'll need to define it within our action URL's query string. The structure for this is ?_method=PUT
, where PUT
is the Http Method we want our request spoofed too.
// received by POST: /posts <form method="POST" action="/posts"></form> // received by PUT: /posts <form method="POST" action="/posts?_method=PUT"></form> // received by PATCH: /posts <form method="POST" action="/posts?_method=PATCH"></form> // received by DELETE: /posts <form method="POST" action="/posts?_method=DELETE"></form>
Copied!
Above the routes are hard coded for clearness, but we can also apply this using the route
method as well.
// received by POST: /posts <form method="POST" action="{{ route('posts.store') }}" ></form> // received by PUT: /posts <form method="POST" action="{{ route('posts.update', {}, { qs: { _method: 'PUT' } }) }}" ></form> // received by PATCH: /posts <form method="POST" action="{{ route('posts.pubish', {}, { qs: { _method: 'PATCH' } }) }}" ></form> // received by DELETE: /posts <form method="POST" action="{{ route('posts.destroy', {}, { qs: { _method: 'DELETE' } }) }}" ></form>
Copied!
This is great, but using the power of components we can clean this up and make it a lot more readable and reusable!
Http Method Spoofing Helper Components
Now that we’re familiar with Method Spoofing and what it looks like, let’s extract these various spoofed methods into helper EdgeJS Components to make adding these to any page a breeze.
First, go ahead and create the following directory tree, if needed.
/resources/views/components/forms/
We’ll be adding all our form helper components here. By adding our EdgeJS Components inside the resources/views/components
directory, we can simplify how we use our methods because AdonisJS binds these components directly to a tag name.
Here’s how we’d need to use them if we put them anywhere else:
@component('path/to/component/forms/post', {}) {{-- form contents --}} @end
Copied!
Here’s how we can use them thanks to placing them at resources/views/components
:
@forms.post({}) {{-- form contents --}} @end
Copied!
As you can see, the latter is super concise and easy to read!
POST Helper Component
Our POST Method helper component will be the most straightforward since it’s the native HTML behavior, so we’ll start here. Let’s start by creating a file for it called post.edge
.
{{-- /resources/views/components/forms/post.edge --}} <form method="POST" action="{{ action }}"> {{{ await $slots.main() }}} </form>
Copied!
Note: {{{ await $slots.main() }}}
will render anything we put inside the component’s tags, it’s the same premise as slots in Vue or React.
Using the POST Helper Component
When it comes to using our post helper component, all we need to add is:
@forms.post({ action: route('posts.store') }) {{-- form content --}} @end
Copied!
PUT Helper Component
From here out we’ll need to add our method spoofing designation to the action’s URL. There are several different ways to go about this. The most straightforward way I could think of was to add it directly to our action
variable.
{{-- /resources/views/components/forms/put.edge --}} @set('action', action.includes('?') ? `${action}&_method=PUT` : `${action}?_method=PUT` ) <form method="POST" action="{{ action }}"> {{{ await $slots.main() }}} </form>
Copied!
So, for our action
variable we're checking to see if it already includes a query string by checking for the presence of the ?
character. If it does we'll add it to the end of the query strings, otherwise, we'll start it as the query string.
Using the PUT Helper Component
Thanks to the component taking care of the spoofing for us, the usage for PUT will look as simple as our POST.
@forms.put({ action: route('posts.update') }) {{-- form content --}} @end
Copied!
PATCH & DELETE Helper Components
For PATCH & DELETE, all we need to do is copy/paste our PUT component and update the Method Spoofing value in our action’s URL.
{{-- /resources/views/components/forms/patch.edge --}} @set('action', action.includes('?') ? `${action}&_method=PATCH` // 👈 set to PATCH : `${action}?_method=PATCH` // 👈 set to PATCH ) <form method="POST" action="{{ action }}"> {{{ await $slots.main() }}} </form>
Copied!
PATCH is now ready to go:
@forms.patch({ action: route('posts.publish') }) {{-- form content --}} @end
Copied!
Then, do the same for DELETE
{{-- /resources/views/components/forms/delete.edge --}} @set('action', action.includes('?') ? `${action}&_method=DELETE` // 👈 set to DELETE : `${action}?_method=DELETE` // 👈 set to DELETE ) <form method="POST" action="{{ action }}"> {{{ await $slots.main() }}} </form>
Copied!
DELETE is now ready to go:
@forms.delete({ action: route('posts.destroy') }) {{-- form content --}} @end
Copied!
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!