rapidoc 9.3.3 → 9.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflow/words.yaml +22 -0
- package/README.md +2 -7
- package/dist/index.html +1 -1
- package/dist/index.html.gz +0 -0
- package/dist/rapidoc-min.js +858 -748
- package/dist/rapidoc-min.js.LICENSE.txt +14 -9
- package/dist/rapidoc-min.js.LICENSE.txt.gz +0 -0
- package/dist/rapidoc-min.js.gz +0 -0
- package/dist/rapidoc-min.js.map +1 -1
- package/dist/rapidoc-min.js.map.gz +0 -0
- package/dist/rapidoc.js +11948 -32008
- package/dist/report.html +6 -5
- package/index.html +2 -1
- package/package.json +25 -24
- package/src/components/api-request.js +266 -122
- package/src/components/api-response.js +11 -10
- package/src/components/json-tree.js +17 -12
- package/src/components/schema-table.js +58 -49
- package/src/components/schema-tree.js +60 -56
- package/src/components/tag-input.js +7 -4
- package/src/json-schema-viewer.js +2 -1
- package/src/rapidoc-mini.js +1 -1
- package/src/rapidoc.js +108 -35
- package/src/styles/endpoint-styles.js +1 -1
- package/src/styles/info-styles.js +2 -1
- package/src/styles/input-styles.js +2 -16
- package/src/styles/nav-styles.js +57 -10
- package/src/styles/schema-styles.js +27 -15
- package/src/styles/tab-styles.js +1 -0
- package/src/templates/advance-search-template.js +3 -3
- package/src/templates/callback-template.js +3 -3
- package/src/templates/code-samples-template.js +1 -0
- package/src/templates/components-template.js +3 -5
- package/src/templates/endpoint-template.js +39 -26
- package/src/templates/expanded-endpoint-template.js +58 -9
- package/src/templates/focused-endpoint-template.js +5 -2
- package/src/templates/header-template.js +2 -2
- package/src/templates/json-schema-viewer-template.js +2 -1
- package/src/templates/main-body-template.js +19 -18
- package/src/templates/navbar-template.js +99 -82
- package/src/templates/overview-template.js +1 -1
- package/src/templates/security-scheme-template.js +51 -27
- package/src/templates/server-template.js +1 -1
- package/src/utils/common-utils.js +2 -2
- package/src/utils/schema-utils.js +192 -67
- package/src/utils/spec-parser.js +9 -3
- package/src/utils/theme.js +9 -3
- package/webpack.config.js +2 -1
|
@@ -60,8 +60,10 @@ export default class ApiRequest extends LitElement {
|
|
|
60
60
|
responseHeaders: { type: String, attribute: false },
|
|
61
61
|
responseStatus: { type: String, attribute: false },
|
|
62
62
|
responseUrl: { type: String, attribute: false },
|
|
63
|
+
curlSyntax: { type: String, attribute: false },
|
|
63
64
|
fillRequestFieldsWithExample: { type: String, attribute: 'fill-request-fields-with-example' },
|
|
64
65
|
allowTry: { type: String, attribute: 'allow-try' },
|
|
66
|
+
showCurlBeforeTry: { type: String, attribute: 'show-curl-before-try' },
|
|
65
67
|
renderStyle: { type: String, attribute: 'render-style' },
|
|
66
68
|
schemaStyle: { type: String, attribute: 'schema-style' },
|
|
67
69
|
activeSchemaTab: { type: String, attribute: 'active-schema-tab' },
|
|
@@ -98,7 +100,9 @@ export default class ApiRequest extends LitElement {
|
|
|
98
100
|
PrismStyles,
|
|
99
101
|
css`
|
|
100
102
|
*, *:before, *:after { box-sizing: border-box; }
|
|
101
|
-
|
|
103
|
+
:where(button, input[type="checkbox"], [tabindex="0"]):focus-visible { box-shadow: var(--focus-shadow); }
|
|
104
|
+
:where(input[type="text"], input[type="password"], select, textarea):focus-visible { border-color: var(--primary-color); }
|
|
105
|
+
tag-input:focus-within { outline: 1px solid;}
|
|
102
106
|
.read-mode {
|
|
103
107
|
margin-top: 24px;
|
|
104
108
|
}
|
|
@@ -213,20 +217,27 @@ export default class ApiRequest extends LitElement {
|
|
|
213
217
|
`;
|
|
214
218
|
}
|
|
215
219
|
|
|
216
|
-
|
|
217
|
-
|
|
220
|
+
async updated() {
|
|
221
|
+
if (this.showCurlBeforeTry === 'true') {
|
|
222
|
+
this.applyCURLSyntax(this.shadowRoot);
|
|
223
|
+
}
|
|
224
|
+
|
|
218
225
|
// In focused mode after rendering the request component, update the text-areas(which contains examples) using
|
|
219
226
|
// the original values from hidden textareas
|
|
220
227
|
// This is done coz, user may update the dom by editing the textarea's and once the DOM is updated externally change detection wont happen, therefore update the values manually
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
228
|
+
|
|
229
|
+
// if (this.renderStyle === 'focused') {
|
|
230
|
+
// if (changedProperties.size === 1 && changedProperties.has('activeSchemaTab')) {
|
|
231
|
+
// // dont update example as only tabs is switched
|
|
232
|
+
// } else {
|
|
233
|
+
// this.requestUpdate();
|
|
234
|
+
// }
|
|
235
|
+
// }
|
|
236
|
+
|
|
237
|
+
if (this.webhook === 'true') {
|
|
238
|
+
this.allowTry = 'false';
|
|
227
239
|
}
|
|
228
240
|
}
|
|
229
|
-
*/
|
|
230
241
|
|
|
231
242
|
async saveExampleState() {
|
|
232
243
|
if (this.renderStyle === 'focused') {
|
|
@@ -259,28 +270,24 @@ export default class ApiRequest extends LitElement {
|
|
|
259
270
|
}
|
|
260
271
|
}
|
|
261
272
|
|
|
273
|
+
/* eslint-disable indent */
|
|
262
274
|
renderExample(example, paramType, paramName) {
|
|
263
275
|
return html`
|
|
264
276
|
${paramType === 'array' ? '[' : ''}
|
|
265
277
|
<a
|
|
266
278
|
part="anchor anchor-param-example"
|
|
279
|
+
style="display:inline-block; min-width:24px; text-align:center"
|
|
267
280
|
class="${this.allowTry === 'true' ? '' : 'inactive-link'}"
|
|
268
281
|
data-example-type="${paramType === 'array' ? paramType : 'string'}"
|
|
269
|
-
data-example="${example.value && Array.isArray(example.value) ? example.value?.join('~|~') : example.value || ''}"
|
|
282
|
+
data-example="${example.value && Array.isArray(example.value) ? example.value?.join('~|~') : (typeof example.value === 'object' ? JSON.stringify(example.value, null, 2) : example.value) || ''}"
|
|
283
|
+
title="${example.value && Array.isArray(example.value) ? example.value?.join('~|~') : (typeof example.value === 'object' ? JSON.stringify(example.value, null, 2) : example.value) || ''}"
|
|
270
284
|
@click="${(e) => {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}"
|
|
281
|
-
>
|
|
282
|
-
${example.value && Array.isArray(example.value) ? example.value?.join(', ') : example.value || '∅'}
|
|
283
|
-
</a>
|
|
285
|
+
const inputEl = e.target.closest('table').querySelector(`[data-pname="${paramName}"]`);
|
|
286
|
+
if (inputEl) {
|
|
287
|
+
inputEl.value = e.target.dataset.exampleType === 'array' ? e.target.dataset.example.split('~|~') : e.target.dataset.example;
|
|
288
|
+
}
|
|
289
|
+
}}"
|
|
290
|
+
> ${example.printableValue || example.value} </a>
|
|
284
291
|
${paramType === 'array' ? '] ' : ''}
|
|
285
292
|
`;
|
|
286
293
|
}
|
|
@@ -303,17 +310,15 @@ export default class ApiRequest extends LitElement {
|
|
|
303
310
|
</ul>`;
|
|
304
311
|
}
|
|
305
312
|
|
|
306
|
-
/* eslint-disable indent */
|
|
307
|
-
|
|
308
313
|
exampleListTemplate(paramName, paramType, exampleList = []) {
|
|
309
|
-
return html` ${
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
314
|
+
return html` ${
|
|
315
|
+
exampleList.length > 0
|
|
316
|
+
? html`<span style="font-weight:bold">Examples: </span>
|
|
317
|
+
${anyExampleWithSummaryOrDescription(exampleList)
|
|
313
318
|
? this.renderLongFormatExamples(exampleList, paramType, paramName)
|
|
314
|
-
: this.renderShortFormatExamples(exampleList, paramType, paramName)
|
|
315
|
-
|
|
316
|
-
|
|
319
|
+
: this.renderShortFormatExamples(exampleList, paramType, paramName)}`
|
|
320
|
+
: ''
|
|
321
|
+
}`;
|
|
317
322
|
}
|
|
318
323
|
|
|
319
324
|
inputParametersTemplate(paramType) {
|
|
@@ -336,7 +341,7 @@ export default class ApiRequest extends LitElement {
|
|
|
336
341
|
for (const param of filteredParams) {
|
|
337
342
|
const [declaredParamSchema, serializeStyle, mimeTypeElem] = getSchemaFromParam(param);
|
|
338
343
|
if (!declaredParamSchema) {
|
|
339
|
-
continue;
|
|
344
|
+
continue;
|
|
340
345
|
}
|
|
341
346
|
const paramSchema = getTypeInfo(declaredParamSchema);
|
|
342
347
|
if (!paramSchema) {
|
|
@@ -367,7 +372,7 @@ export default class ApiRequest extends LitElement {
|
|
|
367
372
|
|| nestExampleIfPresent(param.example)
|
|
368
373
|
|| nestExampleIfPresent(mimeTypeElem?.example)
|
|
369
374
|
|| mimeTypeElem?.examples
|
|
370
|
-
|| paramSchema.examples
|
|
375
|
+
|| nestExampleIfPresent(paramSchema.examples)
|
|
371
376
|
|| nestExampleIfPresent(paramSchema.example)
|
|
372
377
|
),
|
|
373
378
|
paramSchema.type,
|
|
@@ -449,8 +454,12 @@ export default class ApiRequest extends LitElement {
|
|
|
449
454
|
data-param-allow-reserved = "${paramAllowReserved}"
|
|
450
455
|
data-x-fill-example = "${param['x-fill-example'] || 'yes'}"
|
|
451
456
|
spellcheck = "false"
|
|
452
|
-
.textContent="${param['x-fill-example'] === 'no' ? '' : live(this.fillRequestFieldsWithExample === 'true' ? example.exampleVal : '')}"
|
|
457
|
+
.textContent="${param['x-fill-example'] === 'no' ? '' : live(this.fillRequestFieldsWithExample === 'true' ? (typeof example.exampleVal === 'object' ? JSON.stringify(example.exampleVal, null, 2) : example.exampleVal) : '')}"
|
|
453
458
|
style = "resize:vertical; width:100%; height: ${'read focused'.includes(this.renderStyle) ? '180px' : '120px'};"
|
|
459
|
+
@input=${(e) => {
|
|
460
|
+
const requestPanelEl = this.getRequestPanel(e);
|
|
461
|
+
this.liveCURLSyntaxUpdate(requestPanelEl);
|
|
462
|
+
}}
|
|
454
463
|
></textarea>
|
|
455
464
|
</div>`
|
|
456
465
|
: html`
|
|
@@ -461,12 +470,12 @@ export default class ApiRequest extends LitElement {
|
|
|
461
470
|
.data = '${schemaAsObj}'
|
|
462
471
|
schema-expand-level = "${this.schemaExpandLevel}"
|
|
463
472
|
schema-description-expanded = "${this.schemaDescriptionExpanded}"
|
|
464
|
-
allow-schema-description-expand-toggle = "${this.allowSchemaDescriptionExpandToggle}"
|
|
473
|
+
allow-schema-description-expand-toggle = "${this.allowSchemaDescriptionExpandToggle}"
|
|
465
474
|
schema-hide-read-only = "${this.schemaHideReadOnly.includes(this.method)}"
|
|
466
475
|
schema-hide-write-only = "${this.schemaHideWriteOnly.includes(this.method)}"
|
|
467
|
-
exportparts = "btn:btn, btn-fill:btn-fill, btn-outline:btn-outline, btn-try:btn-try, btn-clear:btn-clear, btn-clear-resp:btn-clear-resp,
|
|
468
|
-
|
|
469
|
-
|
|
476
|
+
exportparts = "wrap-request-btn:wrap-request-btn, btn:btn, btn-fill:btn-fill, btn-outline:btn-outline, btn-try:btn-try, btn-clear:btn-clear, btn-clear-resp:btn-clear-resp,
|
|
477
|
+
file-input:file-input, textbox:textbox, textbox-param:textbox-param, textarea:textarea, textarea-param:textarea-param,
|
|
478
|
+
anchor:anchor, anchor-param-example:anchor-param-example"
|
|
470
479
|
> </schema-tree>
|
|
471
480
|
</div>`
|
|
472
481
|
}
|
|
@@ -482,6 +491,10 @@ export default class ApiRequest extends LitElement {
|
|
|
482
491
|
data-x-fill-example = "${param['x-fill-example'] || 'yes'}"
|
|
483
492
|
data-array="false"
|
|
484
493
|
.value="${param['x-fill-example'] === 'no' ? '' : live(this.fillRequestFieldsWithExample === 'true' ? example.exampleVal : '')}"
|
|
494
|
+
@input=${(e) => {
|
|
495
|
+
const requestPanelEl = this.getRequestPanel(e);
|
|
496
|
+
this.liveCURLSyntaxUpdate(requestPanelEl);
|
|
497
|
+
}}
|
|
485
498
|
/>`
|
|
486
499
|
}
|
|
487
500
|
</td>`
|
|
@@ -530,18 +543,18 @@ export default class ApiRequest extends LitElement {
|
|
|
530
543
|
return html`
|
|
531
544
|
<div class="table-title top-gap">${title}</div>
|
|
532
545
|
<div style="display:block; overflow-x:auto; max-width:100%;">
|
|
533
|
-
<table class="m-table" style="width:100%; word-break:break-word;">
|
|
546
|
+
<table role="presentation" class="m-table" style="width:100%; word-break:break-word;">
|
|
534
547
|
${tableRows}
|
|
535
548
|
</table>
|
|
536
549
|
</div>`;
|
|
537
550
|
}
|
|
538
551
|
|
|
539
|
-
// This method is called before navigation change in
|
|
540
|
-
async
|
|
552
|
+
// This method is called before navigation change in focused mode
|
|
553
|
+
async beforeNavigationFocusedMode() {
|
|
541
554
|
// this.saveExampleState();
|
|
542
555
|
}
|
|
543
556
|
|
|
544
|
-
// This method is called after navigation change in
|
|
557
|
+
// This method is called after navigation change in focused mode
|
|
545
558
|
async afterNavigationFocusedMode() {
|
|
546
559
|
this.selectedRequestBodyType = '';
|
|
547
560
|
this.selectedRequestBodyExample = '';
|
|
@@ -557,6 +570,9 @@ export default class ApiRequest extends LitElement {
|
|
|
557
570
|
const readOnlyExampleEl = selectEl.closest('.example-panel').querySelector('.request-body-param');
|
|
558
571
|
const userInputExampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param-user-input');
|
|
559
572
|
userInputExampleTextareaEl.value = readOnlyExampleEl.innerText;
|
|
573
|
+
|
|
574
|
+
const requestPanelEl = this.getRequestPanel({ target: selectEl });
|
|
575
|
+
this.liveCURLSyntaxUpdate(requestPanelEl);
|
|
560
576
|
}, 0, exampleDropdownEl);
|
|
561
577
|
}
|
|
562
578
|
|
|
@@ -672,6 +688,16 @@ export default class ApiRequest extends LitElement {
|
|
|
672
688
|
data-example-format = "${v.exampleFormat}"
|
|
673
689
|
style="width:100%; resize:vertical;"
|
|
674
690
|
.textContent = "${this.fillRequestFieldsWithExample === 'true' ? (v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 2)) : ''}"
|
|
691
|
+
@input=${(e) => {
|
|
692
|
+
const requestPanelEl = this.getRequestPanel(e);
|
|
693
|
+
this.liveCURLSyntaxUpdate(requestPanelEl);
|
|
694
|
+
}}
|
|
695
|
+
@keydown=${(e) => {
|
|
696
|
+
if ((e.keyCode === 10 || e.keyCode === 13) && e.ctrlKey) {
|
|
697
|
+
return this.onTryClick(e);
|
|
698
|
+
}
|
|
699
|
+
}}
|
|
700
|
+
|
|
675
701
|
></textarea>
|
|
676
702
|
</div>
|
|
677
703
|
`)}
|
|
@@ -717,7 +743,7 @@ export default class ApiRequest extends LitElement {
|
|
|
717
743
|
.data = '${schemaAsObj}'
|
|
718
744
|
schema-expand-level = "${this.schemaExpandLevel}"
|
|
719
745
|
schema-description-expanded = "${this.schemaDescriptionExpanded}"
|
|
720
|
-
allow-schema-description-expand-toggle = "${this.allowSchemaDescriptionExpandToggle}"
|
|
746
|
+
allow-schema-description-expand-toggle = "${this.allowSchemaDescriptionExpandToggle}"
|
|
721
747
|
schema-hide-read-only = "${this.schemaHideReadOnly}"
|
|
722
748
|
schema-hide-write-only = "${this.schemaHideWriteOnly}"
|
|
723
749
|
exportparts = "schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
|
|
@@ -732,7 +758,7 @@ export default class ApiRequest extends LitElement {
|
|
|
732
758
|
.data = "${schemaAsObj}"
|
|
733
759
|
schema-expand-level = "${this.schemaExpandLevel}"
|
|
734
760
|
schema-description-expanded = "${this.schemaDescriptionExpanded}"
|
|
735
|
-
allow-schema-description-expand-toggle = "${this.allowSchemaDescriptionExpandToggle}"
|
|
761
|
+
allow-schema-description-expand-toggle = "${this.allowSchemaDescriptionExpandToggle}"
|
|
736
762
|
schema-hide-read-only = "${this.schemaHideReadOnly}"
|
|
737
763
|
schema-hide-write-only = "${this.schemaHideWriteOnly}"
|
|
738
764
|
exportparts = "schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
|
|
@@ -888,7 +914,7 @@ export default class ApiRequest extends LitElement {
|
|
|
888
914
|
data-example = "${Array.isArray(fieldExamples) ? fieldExamples.join('~|~') : fieldExamples}"
|
|
889
915
|
data-array = "true"
|
|
890
916
|
placeholder = "add-multiple ↩"
|
|
891
|
-
.value = "${Array.isArray(fieldExamples) ? Array.isArray(fieldExamples[0]) ? fieldExamples[0] :
|
|
917
|
+
.value = "${Array.isArray(fieldExamples) ? Array.isArray(fieldExamples[0]) ? fieldExamples[0] : fieldExamples : []}"
|
|
892
918
|
>
|
|
893
919
|
</tag-input>
|
|
894
920
|
`
|
|
@@ -965,7 +991,7 @@ export default class ApiRequest extends LitElement {
|
|
|
965
991
|
}`);
|
|
966
992
|
}
|
|
967
993
|
return html`
|
|
968
|
-
<table style="width:100%;" class="m-table">
|
|
994
|
+
<table role="presentation" style="width:100%;" class="m-table">
|
|
969
995
|
${formDataTableRows}
|
|
970
996
|
</table>
|
|
971
997
|
`;
|
|
@@ -985,6 +1011,15 @@ export default class ApiRequest extends LitElement {
|
|
|
985
1011
|
`;
|
|
986
1012
|
}
|
|
987
1013
|
|
|
1014
|
+
curlSyntaxTemplate(display = 'flex') {
|
|
1015
|
+
return html`
|
|
1016
|
+
<div class="col m-markdown" style="flex:1; display:${display}; position:relative; max-width: 100%;">
|
|
1017
|
+
<button class="toolbar-btn" style = "position:absolute; top:12px; right:8px" @click='${(e) => { copyToClipboard(this.curlSyntax.replace(/\\$/, ''), e); }}' part="btn btn-fill"> Copy </button>
|
|
1018
|
+
<pre style="white-space:pre"><code>${unsafeHTML(Prism.highlight(this.curlSyntax.trim().replace(/\\$/, ''), Prism.languages.shell, 'shell'))}</code></pre>
|
|
1019
|
+
</div>
|
|
1020
|
+
`;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
988
1023
|
apiResponseTabTemplate() {
|
|
989
1024
|
let responseFormat = '';
|
|
990
1025
|
let responseContent = '';
|
|
@@ -1017,15 +1052,21 @@ export default class ApiRequest extends LitElement {
|
|
|
1017
1052
|
}}">
|
|
1018
1053
|
<button class="tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}" data-tab = 'response' > RESPONSE</button>
|
|
1019
1054
|
<button class="tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}" data-tab = 'headers' > RESPONSE HEADERS</button>
|
|
1020
|
-
|
|
1055
|
+
${this.showCurlBeforeTry === 'true'
|
|
1056
|
+
? ''
|
|
1057
|
+
: html`<button class="tab-btn ${this.activeResponseTab === 'curl' ? 'active' : ''}" data-tab = 'curl'>CURL</button>`}
|
|
1021
1058
|
</div>
|
|
1022
1059
|
${this.responseIsBlob
|
|
1023
1060
|
? html`
|
|
1024
1061
|
<div class="tab-content col" style="flex:1; display:${this.activeResponseTab === 'response' ? 'flex' : 'none'};">
|
|
1062
|
+
${this.responseBlobType === 'image'
|
|
1063
|
+
? html`<img style="max-height:var(--resp-area-height, 400px); object-fit:contain;" class="mar-top-8" src="${this.responseBlobUrl}"></img>`
|
|
1064
|
+
: ''
|
|
1065
|
+
}
|
|
1025
1066
|
<button class="m-btn thin-border mar-top-8" style="width:135px" @click='${(e) => { downloadResource(this.responseBlobUrl, this.respContentDisposition, e); }}' part="btn btn-outline">
|
|
1026
1067
|
DOWNLOAD
|
|
1027
1068
|
</button>
|
|
1028
|
-
${this.responseBlobType === 'view'
|
|
1069
|
+
${this.responseBlobType === 'view' || this.responseBlobType === 'image'
|
|
1029
1070
|
? html`<button class="m-btn thin-border mar-top-8" style="width:135px" @click='${(e) => { viewResource(this.responseBlobUrl, e); }}' part="btn btn-outline">VIEW (NEW TAB)</button>`
|
|
1030
1071
|
: ''
|
|
1031
1072
|
}
|
|
@@ -1040,10 +1081,7 @@ export default class ApiRequest extends LitElement {
|
|
|
1040
1081
|
<button class="toolbar-btn" style = "position:absolute; top:12px; right:8px" @click='${(e) => { copyToClipboard(this.responseHeaders, e); }}' part="btn btn-fill"> Copy </button>
|
|
1041
1082
|
<pre style="white-space:pre"><code>${unsafeHTML(Prism.highlight(this.responseHeaders, Prism.languages.css, 'css'))}</code></pre>
|
|
1042
1083
|
</div>
|
|
1043
|
-
|
|
1044
|
-
<button class="toolbar-btn" style = "position:absolute; top:12px; right:8px" @click='${(e) => { copyToClipboard(this.curlSyntax.replace(/\\$/, ''), e); }}' part="btn btn-fill"> Copy </button>
|
|
1045
|
-
<pre style="white-space:pre"><code>${unsafeHTML(Prism.highlight(this.curlSyntax.trim().replace(/\\$/, ''), Prism.languages.shell, 'shell'))}</code></pre>
|
|
1046
|
-
</div>
|
|
1084
|
+
${this.showCurlBeforeTry === 'true' ? '' : this.curlSyntaxTemplate(this.activeResponseTab === 'curl' ? 'flex' : 'none')}
|
|
1047
1085
|
</div>`;
|
|
1048
1086
|
}
|
|
1049
1087
|
|
|
@@ -1073,7 +1111,7 @@ export default class ApiRequest extends LitElement {
|
|
|
1073
1111
|
`;
|
|
1074
1112
|
|
|
1075
1113
|
return html`
|
|
1076
|
-
<div style="display:flex; align-items:flex-end; margin:16px 0; font-size:var(--font-size-small);">
|
|
1114
|
+
<div style="display:flex; align-items:flex-end; margin:16px 0; font-size:var(--font-size-small);" part="wrap-request-btn">
|
|
1077
1115
|
<div class="hide-in-small-screen" style="flex-direction:column; margin:0; width:calc(100% - 60px);">
|
|
1078
1116
|
<div style="display:flex; flex-direction:row; align-items:center; overflow:hidden;">
|
|
1079
1117
|
${selectedServerHtml}
|
|
@@ -1108,6 +1146,9 @@ export default class ApiRequest extends LitElement {
|
|
|
1108
1146
|
}
|
|
1109
1147
|
<button class="m-btn primary thin-border" part="btn btn-try" @click="${this.onTryClick}">TRY</button>
|
|
1110
1148
|
</div>
|
|
1149
|
+
<div class="row" style="font-size:var(--font-size-small); margin:5px 0">
|
|
1150
|
+
${this.showCurlBeforeTry === 'true' ? this.curlSyntaxTemplate() : ''}
|
|
1151
|
+
</div>
|
|
1111
1152
|
${this.responseMessage === '' ? '' : this.apiResponseTabTemplate()}
|
|
1112
1153
|
`;
|
|
1113
1154
|
}
|
|
@@ -1133,27 +1174,12 @@ export default class ApiRequest extends LitElement {
|
|
|
1133
1174
|
requestPanelInputEls.forEach((el) => { el.value = ''; });
|
|
1134
1175
|
}
|
|
1135
1176
|
|
|
1136
|
-
|
|
1137
|
-
// const me = this;
|
|
1138
|
-
const tryBtnEl = e.target;
|
|
1177
|
+
buildFetchURL(requestPanelEl) {
|
|
1139
1178
|
let fetchUrl;
|
|
1140
|
-
let curlUrl;
|
|
1141
|
-
let curl = '';
|
|
1142
|
-
let curlHeaders = '';
|
|
1143
|
-
let curlData = '';
|
|
1144
|
-
let curlForm = '';
|
|
1145
|
-
const respEl = this.closest('.expanded-req-resp-container, .req-resp-container')?.getElementsByTagName('api-response')[0];
|
|
1146
|
-
const acceptHeader = respEl?.selectedMimeType;
|
|
1147
|
-
const requestPanelEl = e.target.closest('.request-panel');
|
|
1148
1179
|
const pathParamEls = [...requestPanelEl.querySelectorAll("[data-ptype='path']")];
|
|
1149
1180
|
const queryParamEls = [...requestPanelEl.querySelectorAll("[data-ptype='query']")];
|
|
1150
1181
|
const queryParamObjTypeEls = [...requestPanelEl.querySelectorAll("[data-ptype='query-object']")];
|
|
1151
|
-
const headerParamEls = [...requestPanelEl.querySelectorAll("[data-ptype='header']")];
|
|
1152
|
-
const requestBodyContainerEl = requestPanelEl.querySelector('.request-body-container');
|
|
1153
1182
|
fetchUrl = this.path;
|
|
1154
|
-
const fetchOptions = {
|
|
1155
|
-
method: this.method.toUpperCase(),
|
|
1156
|
-
};
|
|
1157
1183
|
// Generate URL using Path Params
|
|
1158
1184
|
pathParamEls.map((el) => {
|
|
1159
1185
|
fetchUrl = fetchUrl.replace(`{${el.dataset.pname}}`, encodeURIComponent(el.value));
|
|
@@ -1202,7 +1228,7 @@ export default class ApiRequest extends LitElement {
|
|
|
1202
1228
|
const queryParam = new URLSearchParams();
|
|
1203
1229
|
try {
|
|
1204
1230
|
let queryParamObj = {};
|
|
1205
|
-
const { paramSerializeStyle, paramSerializeExplode } = el.dataset;
|
|
1231
|
+
const { paramSerializeStyle, paramSerializeExplode, pname } = el.dataset;
|
|
1206
1232
|
queryParamObj = Object.assign(queryParamObj, JSON.parse(el.value.replace(/\s+/g, ' ')));
|
|
1207
1233
|
if (el.dataset.paramAllowReserved === 'true') {
|
|
1208
1234
|
queryParamsWithReservedCharsAllowed.push(el.dataset.pname);
|
|
@@ -1215,29 +1241,30 @@ export default class ApiRequest extends LitElement {
|
|
|
1215
1241
|
}
|
|
1216
1242
|
} else {
|
|
1217
1243
|
for (const key in queryParamObj) {
|
|
1244
|
+
const pKey = `${pname}[${key}]`;
|
|
1218
1245
|
if (typeof queryParamObj[key] === 'object') {
|
|
1219
1246
|
if (Array.isArray(queryParamObj[key])) {
|
|
1220
1247
|
if (paramSerializeStyle === 'spaceDelimited') {
|
|
1221
|
-
queryParam.append(
|
|
1248
|
+
queryParam.append(pKey, queryParamObj[key].join(' '));
|
|
1222
1249
|
} else if (paramSerializeStyle === 'pipeDelimited') {
|
|
1223
|
-
queryParam.append(
|
|
1250
|
+
queryParam.append(pKey, queryParamObj[key].join('|'));
|
|
1224
1251
|
} else {
|
|
1225
1252
|
if (paramSerializeExplode === 'true') { // eslint-disable-line no-lonely-if
|
|
1226
1253
|
queryParamObj[key].forEach((v) => {
|
|
1227
|
-
queryParam.append(
|
|
1254
|
+
queryParam.append(pKey, v);
|
|
1228
1255
|
});
|
|
1229
1256
|
} else {
|
|
1230
|
-
queryParam.append(
|
|
1257
|
+
queryParam.append(pKey, queryParamObj[key]);
|
|
1231
1258
|
}
|
|
1232
1259
|
}
|
|
1233
1260
|
}
|
|
1234
1261
|
} else {
|
|
1235
|
-
queryParam.append(
|
|
1262
|
+
queryParam.append(pKey, queryParamObj[key]);
|
|
1236
1263
|
}
|
|
1237
1264
|
}
|
|
1238
1265
|
}
|
|
1239
1266
|
} catch (err) {
|
|
1240
|
-
console.
|
|
1267
|
+
console.error('RapiDoc: unable to parse %s into object', el.value); // eslint-disable-line no-console
|
|
1241
1268
|
}
|
|
1242
1269
|
if (queryParam.toString()) {
|
|
1243
1270
|
urlQueryParamsMap.set(el.dataset.pname, queryParam);
|
|
@@ -1246,7 +1273,6 @@ export default class ApiRequest extends LitElement {
|
|
|
1246
1273
|
}
|
|
1247
1274
|
let urlQueryParamString = '';
|
|
1248
1275
|
if (urlQueryParamsMap.size) {
|
|
1249
|
-
urlQueryParamString = '?';
|
|
1250
1276
|
urlQueryParamsMap.forEach((val, pname) => {
|
|
1251
1277
|
if (queryParamsWithReservedCharsAllowed.includes(pname)) {
|
|
1252
1278
|
urlQueryParamString += `${pname}=`;
|
|
@@ -1258,7 +1284,9 @@ export default class ApiRequest extends LitElement {
|
|
|
1258
1284
|
});
|
|
1259
1285
|
urlQueryParamString = urlQueryParamString.slice(0, -1);
|
|
1260
1286
|
}
|
|
1261
|
-
|
|
1287
|
+
if (urlQueryParamString.length !== 0) {
|
|
1288
|
+
fetchUrl = `${fetchUrl}${fetchUrl.includes('?') ? '&' : '?'}${urlQueryParamString}`;
|
|
1289
|
+
}
|
|
1262
1290
|
|
|
1263
1291
|
// Add authentication Query-Param if provided
|
|
1264
1292
|
this.api_keys
|
|
@@ -1267,23 +1295,21 @@ export default class ApiRequest extends LitElement {
|
|
|
1267
1295
|
fetchUrl = `${fetchUrl}${fetchUrl.includes('?') ? '&' : '?'}${v.name}=${encodeURIComponent(v.finalKeyValue)}`;
|
|
1268
1296
|
});
|
|
1269
1297
|
|
|
1270
|
-
// Final URL for API call
|
|
1271
1298
|
fetchUrl = `${this.serverUrl.replace(/\/$/, '')}${fetchUrl}`;
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1299
|
+
return fetchUrl;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
buildFetchHeaders(requestPanelEl) {
|
|
1303
|
+
const respEl = this.closest('.expanded-req-resp-container, .req-resp-container')?.getElementsByTagName('api-response')[0];
|
|
1304
|
+
const headerParamEls = [...requestPanelEl.querySelectorAll("[data-ptype='header']")];
|
|
1305
|
+
const requestBodyContainerEl = requestPanelEl.querySelector('.request-body-container');
|
|
1306
|
+
const acceptHeader = respEl?.selectedMimeType;
|
|
1279
1307
|
const reqHeaders = new Headers();
|
|
1280
1308
|
if (acceptHeader) {
|
|
1281
1309
|
// Uses the acceptHeader from Response panel
|
|
1282
1310
|
reqHeaders.append('Accept', acceptHeader);
|
|
1283
|
-
curlHeaders += ` -H "Accept: ${acceptHeader}" \\\n`;
|
|
1284
1311
|
} else if (this.accept) {
|
|
1285
1312
|
reqHeaders.append('Accept', this.accept);
|
|
1286
|
-
curlHeaders += ` -H "Accept: ${this.accept}" \\\n`;
|
|
1287
1313
|
}
|
|
1288
1314
|
|
|
1289
1315
|
// Add Authentication Header if provided
|
|
@@ -1291,18 +1317,32 @@ export default class ApiRequest extends LitElement {
|
|
|
1291
1317
|
.filter((v) => (v.in === 'header'))
|
|
1292
1318
|
.forEach((v) => {
|
|
1293
1319
|
reqHeaders.append(v.name, v.finalKeyValue);
|
|
1294
|
-
curlHeaders += ` -H "${v.name}: ${v.finalKeyValue}" \\\n`;
|
|
1295
1320
|
});
|
|
1296
1321
|
|
|
1297
1322
|
// Add Header Params
|
|
1298
1323
|
headerParamEls.map((el) => {
|
|
1299
1324
|
if (el.value) {
|
|
1300
1325
|
reqHeaders.append(el.dataset.pname, el.value);
|
|
1301
|
-
curlHeaders += ` -H "${el.dataset.pname}: ${el.value}" \\\n`;
|
|
1302
1326
|
}
|
|
1303
1327
|
});
|
|
1304
1328
|
|
|
1305
|
-
|
|
1329
|
+
if (requestBodyContainerEl) {
|
|
1330
|
+
const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;
|
|
1331
|
+
// Common for all request-body
|
|
1332
|
+
if (!requestBodyType.includes('form-data')) {
|
|
1333
|
+
// For multipart/form-data dont set the content-type to allow creation of browser generated part boundaries
|
|
1334
|
+
reqHeaders.append('Content-Type', requestBodyType);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
return reqHeaders;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
buildFetchBodyOptions(requestPanelEl) {
|
|
1342
|
+
const requestBodyContainerEl = requestPanelEl.querySelector('.request-body-container');
|
|
1343
|
+
const fetchOptions = {
|
|
1344
|
+
method: this.method.toUpperCase(),
|
|
1345
|
+
};
|
|
1306
1346
|
if (requestBodyContainerEl) {
|
|
1307
1347
|
const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;
|
|
1308
1348
|
if (requestBodyType.includes('form-urlencoded')) {
|
|
@@ -1328,7 +1368,6 @@ export default class ApiRequest extends LitElement {
|
|
|
1328
1368
|
formUrlDynParams.append(prop, JSON.stringify(tmpObj[prop]));
|
|
1329
1369
|
}
|
|
1330
1370
|
fetchOptions.body = formUrlDynParams;
|
|
1331
|
-
curlData = ` -d ${formUrlDynParams.toString()} \\\n`;
|
|
1332
1371
|
}
|
|
1333
1372
|
} else {
|
|
1334
1373
|
// url-encoded Form Params (regular)
|
|
@@ -1347,7 +1386,6 @@ export default class ApiRequest extends LitElement {
|
|
|
1347
1386
|
}
|
|
1348
1387
|
});
|
|
1349
1388
|
fetchOptions.body = formUrlParams;
|
|
1350
|
-
curlData = ` -d ${formUrlParams.toString()} \\\n`;
|
|
1351
1389
|
}
|
|
1352
1390
|
} else if (requestBodyType.includes('form-data')) {
|
|
1353
1391
|
const formDataParams = new FormData();
|
|
@@ -1356,15 +1394,10 @@ export default class ApiRequest extends LitElement {
|
|
|
1356
1394
|
if (el.dataset.array === 'false') {
|
|
1357
1395
|
if (el.type === 'file' && el.files[0]) {
|
|
1358
1396
|
formDataParams.append(el.dataset.pname, el.files[0], el.files[0].name);
|
|
1359
|
-
curlForm += ` -F "${el.dataset.pname}=@${el.files[0].name}" \\\n`;
|
|
1360
1397
|
} else if (el.value) {
|
|
1361
1398
|
formDataParams.append(el.dataset.pname, el.value);
|
|
1362
|
-
curlForm += ` -F "${el.dataset.pname}=${el.value}" \\\n`;
|
|
1363
1399
|
}
|
|
1364
1400
|
} else if (el.value && Array.isArray(el.value)) {
|
|
1365
|
-
el.value.forEach((v) => {
|
|
1366
|
-
curlForm = `${curlForm} -F "${el.dataset.pname}[]=${v}" \\\n`;
|
|
1367
|
-
});
|
|
1368
1401
|
formDataParams.append(el.dataset.pname, el.value.join(','));
|
|
1369
1402
|
}
|
|
1370
1403
|
});
|
|
@@ -1373,34 +1406,27 @@ export default class ApiRequest extends LitElement {
|
|
|
1373
1406
|
const bodyParamFileEl = requestPanelEl.querySelector('.request-body-param-file');
|
|
1374
1407
|
if (bodyParamFileEl?.files[0]) {
|
|
1375
1408
|
fetchOptions.body = bodyParamFileEl.files[0]; // eslint-disable-line prefer-destructuring
|
|
1376
|
-
curlData = ` --data-binary @${bodyParamFileEl.files[0].name} \\\n`;
|
|
1377
1409
|
}
|
|
1378
1410
|
} else if (requestBodyType.includes('json') || requestBodyType.includes('xml') || requestBodyType.includes('text')) {
|
|
1379
1411
|
const exampleTextAreaEl = requestPanelEl.querySelector('.request-body-param-user-input');
|
|
1380
1412
|
if (exampleTextAreaEl?.value) {
|
|
1381
1413
|
fetchOptions.body = exampleTextAreaEl.value;
|
|
1382
|
-
if (requestBodyType.includes('json')) {
|
|
1383
|
-
try {
|
|
1384
|
-
curlData = ` -d '${JSON.stringify(JSON.parse(exampleTextAreaEl.value))}' \\\n`;
|
|
1385
|
-
} catch (err) {
|
|
1386
|
-
// Ignore.
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
if (!curlData) {
|
|
1390
|
-
curlData = ` -d '${exampleTextAreaEl.value.replace(/'/g, '\'"\'"\'')}' \\\n`;
|
|
1391
|
-
}
|
|
1392
1414
|
}
|
|
1393
1415
|
}
|
|
1394
|
-
// Common for all request-body
|
|
1395
|
-
if (!requestBodyType.includes('form-data')) {
|
|
1396
|
-
// For multipart/form-data dont set the content-type to allow creation of browser generated part boundaries
|
|
1397
|
-
reqHeaders.append('Content-Type', requestBodyType);
|
|
1398
|
-
}
|
|
1399
|
-
curlHeaders += ` -H "Content-Type: ${requestBodyType}" \\\n`;
|
|
1400
1416
|
}
|
|
1417
|
+
|
|
1418
|
+
return fetchOptions;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
async onTryClick(e) {
|
|
1422
|
+
const tryBtnEl = e.target;
|
|
1423
|
+
const requestPanelEl = tryBtnEl.closest('.request-panel');
|
|
1424
|
+
const fetchUrl = this.buildFetchURL(requestPanelEl);
|
|
1425
|
+
const fetchOptions = this.buildFetchBodyOptions(requestPanelEl);
|
|
1426
|
+
const reqHeaders = this.buildFetchHeaders(requestPanelEl);
|
|
1401
1427
|
this.responseUrl = '';
|
|
1402
1428
|
this.responseHeaders = [];
|
|
1403
|
-
this.curlSyntax =
|
|
1429
|
+
this.curlSyntax = this.generateCURLSyntax(fetchUrl, reqHeaders, fetchOptions, requestPanelEl);
|
|
1404
1430
|
this.responseStatus = 'success';
|
|
1405
1431
|
this.responseIsBlob = false;
|
|
1406
1432
|
|
|
@@ -1409,22 +1435,28 @@ export default class ApiRequest extends LitElement {
|
|
|
1409
1435
|
URL.revokeObjectURL(this.responseBlobUrl);
|
|
1410
1436
|
this.responseBlobUrl = '';
|
|
1411
1437
|
}
|
|
1412
|
-
this.curlSyntax = `${curl}${curlHeaders}${curlData}${curlForm}`;
|
|
1413
1438
|
if (this.fetchCredentials) {
|
|
1414
1439
|
fetchOptions.credentials = this.fetchCredentials;
|
|
1415
1440
|
}
|
|
1416
1441
|
const controller = new AbortController();
|
|
1417
1442
|
const { signal } = controller;
|
|
1418
1443
|
fetchOptions.headers = reqHeaders;
|
|
1419
|
-
const
|
|
1444
|
+
const tempRequest = { url: fetchUrl, ...fetchOptions };
|
|
1420
1445
|
this.dispatchEvent(new CustomEvent('before-try', {
|
|
1421
1446
|
bubbles: true,
|
|
1422
1447
|
composed: true,
|
|
1423
1448
|
detail: {
|
|
1424
|
-
request:
|
|
1449
|
+
request: tempRequest,
|
|
1425
1450
|
controller,
|
|
1426
1451
|
},
|
|
1427
1452
|
}));
|
|
1453
|
+
const updatedFetchOptions = {
|
|
1454
|
+
method: tempRequest.method,
|
|
1455
|
+
headers: tempRequest.headers,
|
|
1456
|
+
credentials: tempRequest.credentials,
|
|
1457
|
+
body: tempRequest.body,
|
|
1458
|
+
};
|
|
1459
|
+
const fetchRequest = new Request(tempRequest.url, updatedFetchOptions);
|
|
1428
1460
|
|
|
1429
1461
|
let fetchResponse;
|
|
1430
1462
|
let responseClone;
|
|
@@ -1439,6 +1471,23 @@ export default class ApiRequest extends LitElement {
|
|
|
1439
1471
|
const startTime = performance.now();
|
|
1440
1472
|
fetchResponse = await fetch(fetchRequest, { signal });
|
|
1441
1473
|
const endTime = performance.now();
|
|
1474
|
+
// Allow to modify response
|
|
1475
|
+
/*
|
|
1476
|
+
let resolveModifiedResponse; // Create a promise that will be resolved from the event listener
|
|
1477
|
+
const modifiedResponsePromise = new Promise((resolve) => {
|
|
1478
|
+
resolveModifiedResponse = resolve;
|
|
1479
|
+
});
|
|
1480
|
+
this.dispatchEvent(new CustomEvent('fetched-try', {
|
|
1481
|
+
bubbles: true,
|
|
1482
|
+
composed: true,
|
|
1483
|
+
detail: {
|
|
1484
|
+
request: fetchRequest,
|
|
1485
|
+
response: fetchResponse,
|
|
1486
|
+
resolveModifiedResponse, // pass the resolver function
|
|
1487
|
+
},
|
|
1488
|
+
}));
|
|
1489
|
+
fetchResponse = await modifiedResponsePromise; // Wait for the modified response
|
|
1490
|
+
*/
|
|
1442
1491
|
responseClone = fetchResponse.clone(); // create a response clone to allow reading response body again (response.json, response.text etc)
|
|
1443
1492
|
tryBtnEl.disabled = false;
|
|
1444
1493
|
this.responseMessage = html`${fetchResponse.statusText ? `${fetchResponse.statusText}:${fetchResponse.status}` : fetchResponse.status} <div style="color:var(--light-fg)"> Took ${Math.round(endTime - startTime)} milliseconds </div>`;
|
|
@@ -1478,6 +1527,9 @@ export default class ApiRequest extends LitElement {
|
|
|
1478
1527
|
} else if (/^font\/|tar$|zip$|7z$|rtf$|msword$|excel$|\/pdf$|\/octet-stream$|^application\/vnd\./.test(contentType)) {
|
|
1479
1528
|
this.responseIsBlob = true;
|
|
1480
1529
|
this.responseBlobType = 'download';
|
|
1530
|
+
} else if (/^image/.test(contentType)) {
|
|
1531
|
+
this.responseIsBlob = true;
|
|
1532
|
+
this.responseBlobType = 'image';
|
|
1481
1533
|
} else if (/^audio|^image|^video/.test(contentType)) {
|
|
1482
1534
|
this.responseIsBlob = true;
|
|
1483
1535
|
this.responseBlobType = 'view';
|
|
@@ -1522,6 +1574,7 @@ export default class ApiRequest extends LitElement {
|
|
|
1522
1574
|
},
|
|
1523
1575
|
}));
|
|
1524
1576
|
this.responseMessage = 'Request Aborted';
|
|
1577
|
+
this.responseText = 'Request Aborted';
|
|
1525
1578
|
} else {
|
|
1526
1579
|
this.dispatchEvent(new CustomEvent('after-try', {
|
|
1527
1580
|
bubbles: true,
|
|
@@ -1537,6 +1590,96 @@ export default class ApiRequest extends LitElement {
|
|
|
1537
1590
|
this.requestUpdate();
|
|
1538
1591
|
}
|
|
1539
1592
|
|
|
1593
|
+
liveCURLSyntaxUpdate(requestPanelEl) {
|
|
1594
|
+
this.applyCURLSyntax(requestPanelEl);
|
|
1595
|
+
this.requestUpdate();
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
onGenerateCURLClick(e) {
|
|
1599
|
+
const requestPanelEl = this.getRequestPanel(e);
|
|
1600
|
+
this.applyCURLSyntax(requestPanelEl);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
getRequestPanel(e) {
|
|
1604
|
+
return e.target.closest('.request-panel');
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
applyCURLSyntax(requestPanelEl) {
|
|
1608
|
+
const fetchUrl = this.buildFetchURL(requestPanelEl);
|
|
1609
|
+
const fetchOptions = this.buildFetchBodyOptions(requestPanelEl);
|
|
1610
|
+
const fetchHeaders = this.buildFetchHeaders(requestPanelEl);
|
|
1611
|
+
|
|
1612
|
+
this.curlSyntax = this.generateCURLSyntax(fetchUrl, fetchHeaders, fetchOptions, requestPanelEl);
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
generateCURLSyntax(fetchUrl, fetchHeaders, fetchOptions, requestPanelEl) {
|
|
1616
|
+
let curlUrl;
|
|
1617
|
+
let curl = '';
|
|
1618
|
+
let curlHeaders = '';
|
|
1619
|
+
let curlData = '';
|
|
1620
|
+
let curlForm = '';
|
|
1621
|
+
const requestBodyContainerEl = requestPanelEl.querySelector('.request-body-container');
|
|
1622
|
+
|
|
1623
|
+
if (fetchUrl.startsWith('http') === false) {
|
|
1624
|
+
const url = new URL(fetchUrl, window.location.href);
|
|
1625
|
+
curlUrl = url.href;
|
|
1626
|
+
} else {
|
|
1627
|
+
curlUrl = fetchUrl;
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
curl = `curl -X ${this.method.toUpperCase()} "${curlUrl}" \\\n`;
|
|
1631
|
+
|
|
1632
|
+
fetchHeaders.forEach((value, key) => {
|
|
1633
|
+
let tempHeaderArray = value.split(',');
|
|
1634
|
+
tempHeaderArray = tempHeaderArray.map((el) => el.trim()).filter((string, index) => tempHeaderArray.indexOf(string) === index);
|
|
1635
|
+
fetchHeaders.set(key, tempHeaderArray.join(', '));
|
|
1636
|
+
});
|
|
1637
|
+
|
|
1638
|
+
curlHeaders = Array.from(fetchHeaders).map(([key, value]) => ` -H "${key}: ${value}"`).join('\\\n');
|
|
1639
|
+
if (curlHeaders) {
|
|
1640
|
+
curlHeaders = `${curlHeaders} \\\n`;
|
|
1641
|
+
}
|
|
1642
|
+
if (fetchOptions.body instanceof URLSearchParams) {
|
|
1643
|
+
curlData = ` -d ${fetchOptions.body.toString()} \\\n`;
|
|
1644
|
+
} else if (fetchOptions.body instanceof File) {
|
|
1645
|
+
curlData = ` --data-binary @${fetchOptions.body.name} \\\n`;
|
|
1646
|
+
} else if (fetchOptions.body instanceof FormData) {
|
|
1647
|
+
curlForm = Array.from(fetchOptions.body).reduce((aggregator, [key, value]) => {
|
|
1648
|
+
if (value instanceof File) {
|
|
1649
|
+
return [...aggregator, ` -F "${key}=@${value.name}"`];
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
const multiple = value.match(/([^,],)/gm);
|
|
1653
|
+
|
|
1654
|
+
if (multiple) {
|
|
1655
|
+
const multipleResults = multiple.map((one) => `-F "${key}[]=${one}"`);
|
|
1656
|
+
|
|
1657
|
+
return [...aggregator, ...multipleResults];
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
return [...aggregator, ` -F "${key}=${value}"`];
|
|
1661
|
+
}, []).join('\\\n');
|
|
1662
|
+
} else if (requestBodyContainerEl && requestBodyContainerEl.dataset.selectedRequestBodyType) {
|
|
1663
|
+
const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;
|
|
1664
|
+
const exampleTextAreaEl = requestPanelEl.querySelector('.request-body-param-user-input');
|
|
1665
|
+
if (exampleTextAreaEl?.value) {
|
|
1666
|
+
fetchOptions.body = exampleTextAreaEl.value;
|
|
1667
|
+
if (requestBodyType.includes('json')) {
|
|
1668
|
+
try {
|
|
1669
|
+
curlData = ` -d '${JSON.stringify(JSON.parse(exampleTextAreaEl.value))}' \\\n`;
|
|
1670
|
+
} catch (err) {
|
|
1671
|
+
// Ignore.
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
if (!curlData) {
|
|
1675
|
+
curlData = ` -d '${exampleTextAreaEl.value.replace(/'/g, '\'"\'"\'')}' \\\n`;
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
return `${curl}${curlHeaders}${curlData}${curlForm}`;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1540
1683
|
onAddRemoveFileInput(e, pname, ptype) {
|
|
1541
1684
|
if (e.target.tagName.toLowerCase() !== 'button') {
|
|
1542
1685
|
return;
|
|
@@ -1592,7 +1735,8 @@ export default class ApiRequest extends LitElement {
|
|
|
1592
1735
|
}
|
|
1593
1736
|
|
|
1594
1737
|
disconnectedCallback() {
|
|
1595
|
-
|
|
1738
|
+
this.curlSyntax = '';
|
|
1739
|
+
// Cleanup ObjectURL for the blob data if this component created one
|
|
1596
1740
|
if (this.responseBlobUrl) {
|
|
1597
1741
|
URL.revokeObjectURL(this.responseBlobUrl);
|
|
1598
1742
|
this.responseBlobUrl = '';
|