diff --git a/src/components/Preview.vue b/src/components/Preview.vue index 22ade15..0917954 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,36 @@ 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') + 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 +} const submitRequest = async () => { if (url.value) { isLoading.value = true @@ -207,7 +238,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 +251,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 +834,7 @@ const onError = (error) => {

{{ exampleBodyTitle }}:

-
+