From 55d7a4db69ebfe215b62f7ef0bdf451540196d70 Mon Sep 17 00:00:00 2001 From: Hongwei Date: Wed, 26 Aug 2026 20:17:45 +0200 Subject: [PATCH 1/2] fix: read live request body from editor DOM instead of debounced ref The JSON request-body editor (json-editor-vue / vanilla-jsoneditor) syncs its content into the value used on submit via onChange, which is debounced (defaults to 300ms, and still resolves asynchronously even at debounce=0). Submitting immediately after editing the body could race ahead of that sync and send stale or empty content, surfacing as a misleading JSON-format error from the API even though the editor showed valid JSON. Read the request body straight from the CodeMirror editor's DOM instead, which is updated synchronously on every edit, with a fallback to the existing ref if the editor node isn't found. --- src/components/Preview.vue | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/components/Preview.vue b/src/components/Preview.vue index 22ade15..4d82d5a 100644 --- a/src/components/Preview.vue +++ b/src/components/Preview.vue @@ -50,6 +50,7 @@ const successResponseBody = ref('') const isLargeResponse = ref(false) const largeResponseJson = ref(null) const exampleRequestBody = ref('') +const jsonEditorContainerRef = ref(null) const requiredRoles = ref([]) const validations = ref([]) const possibleErrors = ref([]) @@ -197,6 +198,22 @@ const setType = (method) => { } } } +// exampleRequestBody only reflects the editor's content once vanilla- +// jsoneditor's onChange fires, which is debounced (json-editor-vue defaults +// to 300ms, and still resolves asynchronously even with debounce set to 0). +// Submitting immediately after typing or programmatically setting the body +// can race ahead of that sync and send stale (or empty) content. The +// underlying CodeMirror editor's own DOM is updated synchronously on every +// edit, so read the request body straight from there instead of relying on +// the debounced ref. Falls back to exampleRequestBody if the DOM node isn't +// found for any reason (e.g. editor not yet mounted). +const getCurrentRequestBodyText = () => { + const editorContentEl = jsonEditorContainerRef.value?.querySelector?.('.cm-content') + if (editorContentEl) { + return editorContentEl.innerText + } + return exampleRequestBody.value +} const submitRequest = async () => { if (url.value) { isLoading.value = true @@ -207,7 +224,7 @@ const submitRequest = async () => { await create( url.value, (() => { - const rawBody = exampleRequestBody.value + const rawBody = getCurrentRequestBodyText() const maybeBody = typeof rawBody === 'string' ? rawBody.trim() : rawBody return maybeBody ? maybeBody : undefined })() @@ -220,7 +237,7 @@ const submitRequest = async () => { await update( url.value, (() => { - const rawBody = exampleRequestBody.value + const rawBody = getCurrentRequestBodyText() const maybeBody = typeof rawBody === 'string' ? rawBody.trim() : rawBody return maybeBody ? maybeBody : undefined })() @@ -803,7 +820,7 @@ const onError = (error) => {

{{ exampleBodyTitle }}:

-
+
Date: Wed, 26 Aug 2026 22:10:46 +0200 Subject: [PATCH 2/2] fix: validate DOM-read request body before trusting it CodeMirror virtualises rendering for long content -- only the visible viewport is actually present in the DOM -- so getCurrentRequestBodyText() reading .cm-content directly (from the previous fix in this branch) could return truncated, invalid JSON for a sufficiently long example body. That invalid JSON then failed JSON.parse() in the request layer, which silently omits the body on a parse failure, sending no body at all. Validate the DOM read is parseable before trusting it; fall back to the exampleRequestBody ref otherwise, which for an unedited pre-filled example still holds the complete text from the API response untouched by CodeMirror's rendering. --- src/components/Preview.vue | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/components/Preview.vue b/src/components/Preview.vue index 4d82d5a..0917954 100644 --- a/src/components/Preview.vue +++ b/src/components/Preview.vue @@ -209,8 +209,22 @@ const setType = (method) => { // found for any reason (e.g. editor not yet mounted). const getCurrentRequestBodyText = () => { const editorContentEl = jsonEditorContainerRef.value?.querySelector?.('.cm-content') - if (editorContentEl) { - return editorContentEl.innerText + const domText = editorContentEl?.innerText + if (domText) { + try { + // CodeMirror virtualises long content -- only the rendered viewport is + // present in the DOM, so a sufficiently long example can come back + // truncated (and therefore invalid JSON) here even though the + // editor's actual document is complete. Validating before trusting it + // avoids silently submitting a truncated body; fall through to the + // ref below instead, which for an unedited pre-filled example still + // holds the complete text from the API response (never rendered + // through CodeMirror, so never truncated by it). + JSON.parse(domText.trim()) + return domText + } catch (e) { + // fall through to exampleRequestBody.value below + } } return exampleRequestBody.value }