Skip to content

Commit 840ca05

Browse files
authored
Merge pull request #72 from github/srt32-support-other-http-methods
Support alternative HTTP methods
2 parents 342da47 + 059dde3 commit 840ca05

File tree

5 files changed

+66
-25
lines changed

5 files changed

+66
-25
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Note that in the following example the CSRF element is marked with the `data-csr
4747
- `csrf` is the [CSRF][] token for the posted form. It's available in the request body as a `authenticity_token` form parameter.
4848
- You can also supply the CSRF token via a child element. See [usage](#Usage) example.
4949
- `required` is a boolean attribute that requires the validation to succeed before the surrounding form may be submitted.
50+
- `http-method` defaults to `POST` where data is submitted as a POST with form data. You can set `GET` and the HTTP method used will be a get with url encoded params instead.
5051
5152
## Events
5253

custom-elements.json

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,8 @@
5656
},
5757
"members": [
5858
{
59-
"kind": "method",
59+
"kind": "field",
6060
"name": "setValidity",
61-
"parameters": [
62-
{
63-
"name": "message",
64-
"type": {
65-
"text": "string"
66-
}
67-
}
68-
],
6961
"inheritedFrom": {
7062
"name": "AutoCheckValidationEvent",
7163
"module": "src/auto-check-element.ts"
@@ -92,16 +84,8 @@
9284
},
9385
"members": [
9486
{
95-
"kind": "method",
87+
"kind": "field",
9688
"name": "setValidity",
97-
"parameters": [
98-
{
99-
"name": "message",
100-
"type": {
101-
"text": "string"
102-
}
103-
}
104-
],
10589
"inheritedFrom": {
10690
"name": "AutoCheckValidationEvent",
10791
"module": "src/auto-check-element.ts"
@@ -206,6 +190,14 @@
206190
"type": {
207191
"text": "string"
208192
}
193+
},
194+
{
195+
"kind": "field",
196+
"name": "httpMethod",
197+
"type": {
198+
"text": "string"
199+
},
200+
"readonly": true
209201
}
210202
],
211203
"attributes": [

src/auto-check-element.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ type State = {
1212
controller: Controller | null
1313
}
1414

15+
enum AllowedHttpMethods {
16+
GET = 'GET',
17+
POST = 'POST',
18+
}
19+
1520
const states = new WeakMap<AutoCheckElement, State>()
1621

1722
class AutoCheckEvent extends Event {
@@ -176,6 +181,10 @@ export class AutoCheckElement extends HTMLElement {
176181
set csrfField(value: string) {
177182
this.setAttribute('csrf-field', value)
178183
}
184+
185+
get httpMethod(): string {
186+
return AllowedHttpMethods[this.getAttribute('http-method') as keyof typeof AllowedHttpMethods] || 'POST'
187+
}
179188
}
180189

181190
function setLoadingState(event: Event) {
@@ -187,10 +196,11 @@ function setLoadingState(event: Event) {
187196

188197
const src = autoCheckElement.src
189198
const csrf = autoCheckElement.csrf
199+
const httpMethod = autoCheckElement.httpMethod
190200
const state = states.get(autoCheckElement)
191201

192202
// If some attributes are missing we want to exit early and make sure that the element is valid.
193-
if (!src || !csrf || !state) {
203+
if (!src || (httpMethod === 'POST' && !csrf) || !state) {
194204
return
195205
}
196206

@@ -214,6 +224,9 @@ function makeAbortController() {
214224
}
215225

216226
async function fetchWithNetworkEvents(el: Element, url: string, options: RequestInit): Promise<Response> {
227+
if (options.method === 'GET') {
228+
delete options.body
229+
}
217230
try {
218231
const response = await fetch(url, options)
219232
el.dispatchEvent(new Event('load'))
@@ -238,9 +251,10 @@ async function check(autoCheckElement: AutoCheckElement) {
238251
const src = autoCheckElement.src
239252
const csrf = autoCheckElement.csrf
240253
const state = states.get(autoCheckElement)
254+
const httpMethod = autoCheckElement.httpMethod
241255

242256
// If some attributes are missing we want to exit early and make sure that the element is valid.
243-
if (!src || !csrf || !state) {
257+
if (!src || (httpMethod === 'POST' && !csrf) || !state) {
244258
if (autoCheckElement.required) {
245259
input.setCustomValidity('')
246260
}
@@ -255,8 +269,13 @@ async function check(autoCheckElement: AutoCheckElement) {
255269
}
256270

257271
const body = new FormData()
258-
body.append(csrfField, csrf)
259-
body.append('value', input.value)
272+
const url = new URL(src, window.location.origin)
273+
if (httpMethod === 'POST') {
274+
body.append(csrfField, csrf)
275+
body.append('value', input.value)
276+
} else {
277+
url.search = new URLSearchParams({value: input.value}).toString()
278+
}
260279

261280
input.dispatchEvent(new AutoCheckSendEvent(body))
262281

@@ -269,10 +288,10 @@ async function check(autoCheckElement: AutoCheckElement) {
269288
state.controller = makeAbortController()
270289

271290
try {
272-
const response = await fetchWithNetworkEvents(autoCheckElement, src, {
291+
const response = await fetchWithNetworkEvents(autoCheckElement, url.toString(), {
273292
credentials: 'same-origin',
274293
signal: state.controller.signal,
275-
method: 'POST',
294+
method: httpMethod,
276295
body,
277296
})
278297
if (response.ok) {

test/auto-check.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,35 @@ describe('auto-check element', function () {
114114
})
115115
})
116116

117+
describe('using HTTP GET', function () {
118+
let checker
119+
let input
120+
121+
beforeEach(function () {
122+
const container = document.createElement('div')
123+
container.innerHTML = `
124+
<auto-check src="/success" http-method="GET" required>
125+
<input>
126+
</auto-check>`
127+
document.body.append(container)
128+
129+
checker = document.querySelector('auto-check')
130+
input = checker.querySelector('input')
131+
})
132+
133+
afterEach(function () {
134+
document.body.innerHTML = ''
135+
checker = null
136+
input = null
137+
})
138+
139+
it('validates input with successful server response with GET', async function () {
140+
triggerInput(input, 'hub')
141+
await once(input, 'auto-check-complete')
142+
assert.isTrue(input.checkValidity())
143+
})
144+
})
145+
117146
describe('network lifecycle events', function () {
118147
let checker
119148
let input

web-test-runner.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default {
1919
middleware: [
2020
async ({request, response}, next) => {
2121
const {method, path} = request
22-
if (method === 'POST') {
22+
if (method === 'POST' || method === 'GET') {
2323
if (path.startsWith('/fail')) {
2424
response.status = 422
2525
// eslint-disable-next-line i18n-text/no-en

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy