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)