Skip to content

Commit

Permalink
Merge pull request #72 from github/srt32-support-other-http-methods
Browse files Browse the repository at this point in the history
Support alternative HTTP methods
  • Loading branch information
srt32 authored May 29, 2024
2 parents 342da47 + 059dde3 commit 840ca05
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 25 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Note that in the following example the CSRF element is marked with the `data-csr
- `csrf` is the [CSRF][] token for the posted form. It's available in the request body as a `authenticity_token` form parameter.
- You can also supply the CSRF token via a child element. See [usage](#Usage) example.
- `required` is a boolean attribute that requires the validation to succeed before the surrounding form may be submitted.
- `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.
## Events
Expand Down
28 changes: 10 additions & 18 deletions custom-elements.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,8 @@
},
"members": [
{
"kind": "method",
"kind": "field",
"name": "setValidity",
"parameters": [
{
"name": "message",
"type": {
"text": "string"
}
}
],
"inheritedFrom": {
"name": "AutoCheckValidationEvent",
"module": "src/auto-check-element.ts"
Expand All @@ -92,16 +84,8 @@
},
"members": [
{
"kind": "method",
"kind": "field",
"name": "setValidity",
"parameters": [
{
"name": "message",
"type": {
"text": "string"
}
}
],
"inheritedFrom": {
"name": "AutoCheckValidationEvent",
"module": "src/auto-check-element.ts"
Expand Down Expand Up @@ -206,6 +190,14 @@
"type": {
"text": "string"
}
},
{
"kind": "field",
"name": "httpMethod",
"type": {
"text": "string"
},
"readonly": true
}
],
"attributes": [
Expand Down
31 changes: 25 additions & 6 deletions src/auto-check-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ type State = {
controller: Controller | null
}

enum AllowedHttpMethods {
GET = 'GET',
POST = 'POST',
}

const states = new WeakMap<AutoCheckElement, State>()

class AutoCheckEvent extends Event {
Expand Down Expand Up @@ -176,6 +181,10 @@ export class AutoCheckElement extends HTMLElement {
set csrfField(value: string) {
this.setAttribute('csrf-field', value)
}

get httpMethod(): string {
return AllowedHttpMethods[this.getAttribute('http-method') as keyof typeof AllowedHttpMethods] || 'POST'
}
}

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

const src = autoCheckElement.src
const csrf = autoCheckElement.csrf
const httpMethod = autoCheckElement.httpMethod
const state = states.get(autoCheckElement)

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

Expand All @@ -214,6 +224,9 @@ function makeAbortController() {
}

async function fetchWithNetworkEvents(el: Element, url: string, options: RequestInit): Promise<Response> {
if (options.method === 'GET') {
delete options.body
}
try {
const response = await fetch(url, options)
el.dispatchEvent(new Event('load'))
Expand All @@ -238,9 +251,10 @@ async function check(autoCheckElement: AutoCheckElement) {
const src = autoCheckElement.src
const csrf = autoCheckElement.csrf
const state = states.get(autoCheckElement)
const httpMethod = autoCheckElement.httpMethod

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

const body = new FormData()
body.append(csrfField, csrf)
body.append('value', input.value)
const url = new URL(src, window.location.origin)
if (httpMethod === 'POST') {
body.append(csrfField, csrf)
body.append('value', input.value)
} else {
url.search = new URLSearchParams({value: input.value}).toString()
}

input.dispatchEvent(new AutoCheckSendEvent(body))

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

try {
const response = await fetchWithNetworkEvents(autoCheckElement, src, {
const response = await fetchWithNetworkEvents(autoCheckElement, url.toString(), {
credentials: 'same-origin',
signal: state.controller.signal,
method: 'POST',
method: httpMethod,
body,
})
if (response.ok) {
Expand Down
29 changes: 29 additions & 0 deletions test/auto-check.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,35 @@ describe('auto-check element', function () {
})
})

describe('using HTTP GET', function () {
let checker
let input

beforeEach(function () {
const container = document.createElement('div')
container.innerHTML = `
<auto-check src="/success" http-method="GET" required>
<input>
</auto-check>`
document.body.append(container)

checker = document.querySelector('auto-check')
input = checker.querySelector('input')
})

afterEach(function () {
document.body.innerHTML = ''
checker = null
input = null
})

it('validates input with successful server response with GET', async function () {
triggerInput(input, 'hub')
await once(input, 'auto-check-complete')
assert.isTrue(input.checkValidity())
})
})

describe('network lifecycle events', function () {
let checker
let input
Expand Down
2 changes: 1 addition & 1 deletion web-test-runner.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default {
middleware: [
async ({request, response}, next) => {
const {method, path} = request
if (method === 'POST') {
if (method === 'POST' || method === 'GET') {
if (path.startsWith('/fail')) {
response.status = 422
// eslint-disable-next-line i18n-text/no-en
Expand Down

0 comments on commit 840ca05

Please sign in to comment.