Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions src/components/Preview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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([])
Expand Down Expand Up @@ -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
Expand All @@ -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
})()
Expand All @@ -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
})()
Expand Down Expand Up @@ -803,7 +834,7 @@ const onError = (error) => {
</div>
<div class="json-editor-container" v-show="method === 'POST' || method === 'PUT' || method === 'DELETE'">
<p class="header-container request-body-header">{{ exampleBodyTitle }}:</p>
<div class="json-editor jse-theme-dark">
<div class="json-editor jse-theme-dark" ref="jsonEditorContainerRef">
<JsonEditorVue
v-model="exampleRequestBody"
:stringified="true"
Expand Down