feat: REST API request execution from docs for GET requests#1000
feat: REST API request execution from docs for GET requests#1000Yash-Raj-5424 wants to merge 12 commits intolayer5io:masterfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces interactive REST API documentation features, allowing users to execute GET requests directly from the browser. It includes new SCSS for styling, several Hugo partials for UI components (auth, parameters, server selection), and a JavaScript executor to handle the request logic. Feedback focuses on improving the robustness of the JavaScript executor, specifically regarding URL construction, handling multiple occurrences of path parameters, avoiding hardcoded HTTP methods, and optimizing UI updates to prevent performance degradation on pages with many endpoints.
| const urlElements = trySection.querySelectorAll('.rest-api-try-item__url'); | ||
| urlElements.forEach(el => { | ||
| const url = el.textContent.trim(); | ||
| const baseUrl = url.replace(/\/[^/]*$/, ''); // Remove path, keep base |
There was a problem hiding this comment.
The regex /\/[^/]*$/ only removes the last segment of the URL. For an API path with multiple segments (e.g., /api/v1/resource), this will leave an incorrect base URL (e.g., https://example.com/api/v1), leading to duplicated path segments when the final request URL is constructed in buildRequestUrl. A more robust approach would be to pass the base URLs directly from the template via data attributes instead of reverse-engineering them from the DOM.
| extractMethod(operationPanel) { | ||
| const badge = operationPanel.querySelector('.rest-api-method-badge'); | ||
| return badge ? badge.textContent.toLowerCase() : 'get'; | ||
| } |
There was a problem hiding this comment.
The extractMethod function currently scrapes the HTTP method from the UI badge text. Since the method is already provided as a data attribute (data-operation-method) on the operation panel in viewer.html, it is more reliable and efficient to read it directly from the dataset.
extractMethod(operationPanel) {
return operationPanel.dataset.operationMethod || 'get';
}| updatePreviewUrl() { | ||
| const panels = document.querySelectorAll('[data-operation-panel]'); | ||
| panels.forEach(panel => { | ||
| const preview = panel.querySelector('[data-url-preview]'); | ||
| if (preview) { | ||
| const operation = this.getOperationMetadata(panel); | ||
| const url = this.buildRequestUrl(panel, operation); | ||
| preview.textContent = url; | ||
| } | ||
| }); | ||
| } |
There was a problem hiding this comment.
The updatePreviewUrl function iterates over all operation panels on the page and recalculates their URLs whenever any input changes. This is inefficient, especially for pages with many endpoints (like the 81 mentioned in the PR). It should be refactored to accept a specific panel as an argument and only update the preview for that panel. Additionally, consider using event delegation for the input listeners to improve performance and reduce the number of active listeners.
|
🚀 Preview deployment: https://layer5io.github.io/docs/pr-preview/pr-1000/
|
There was a problem hiding this comment.
Pull request overview
This PR adds an interactive “Execute directly” section to the REST API docs so users can run GET requests in-page (server selection, parameter entry, auth token, URL preview, and response rendering).
Changes:
- Adds a client-side request executor (
fetch+ UI rendering) for GET endpoints. - Introduces new Hugo partials for server selection, URL preview, auth token input, parameter inputs, and the execute button.
- Adds new styling for the interactive components and loads the executor script on the REST API docs layout.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| static/js/rest-api-executor.js | Core request execution logic, parameter handling, URL preview updates, and response/error UI rendering |
| layouts/partials/rest-apis/viewer.html | Adds the “Execute directly” section to GET operations and wires in new partials |
| layouts/partials/rest-apis/url-preview.html | Renders initial URL preview for an operation |
| layouts/partials/rest-apis/server-selector.html | Adds server dropdown to choose the API base URL |
| layouts/partials/rest-apis/parameter-inputs.html | Renders parameter inputs (path/query/header/cookie) for interactive execution |
| layouts/partials/rest-apis/execute-button.html | Adds the execute request button element |
| layouts/partials/rest-apis/auth-input.html | Adds bearer token input + helper link |
| layouts/docs/rest-apis.html | Loads the executor script on the REST APIs docs page |
| assets/scss/rest-api-interactive.scss | Adds styling for the interactive execution UI |
| /* Execute Button */ | ||
| .rest-api-execute-button { | ||
| display: inline-flex; | ||
| align-items: center; | ||
| gap: 0.5rem; | ||
| padding: 0.75rem 1.5rem; | ||
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | ||
| color: white; | ||
| border: none; | ||
| border-radius: 0.375rem; | ||
| font-weight: 600; | ||
| font-size: 0.95rem; | ||
| cursor: pointer; | ||
| transition: all 0.3s ease; | ||
| box-shadow: 0 4px 6px -1px rgba(102, 126, 234, 0.3); | ||
| } |
| /> | ||
| <p class="rest-api-auth-help"> | ||
| Provide a security token for authentication. | ||
| <a href="https://docs.layer5.io/cloud/identity/tokens/" target="_blank"> |
| setupParameterInputs() { | ||
| const inputs = document.querySelectorAll('[data-parameter-input]'); | ||
| inputs.forEach(input => { | ||
| input.addEventListener('change', () => { | ||
| this.updatePreviewUrl(); | ||
| }); | ||
| input.addEventListener('input', () => { | ||
| this.updatePreviewUrl(); | ||
| }); | ||
| }); |
| extractServers(operationPanel) { | ||
| const trySection = operationPanel.querySelector('.rest-api-section--try'); | ||
| if (!trySection) return ['https://cloud.layer5.io']; | ||
|
|
||
| const servers = []; | ||
| const urlElements = trySection.querySelectorAll('.rest-api-try-item__url'); | ||
| urlElements.forEach(el => { | ||
| const url = el.textContent.trim(); | ||
| const baseUrl = url.replace(/\/[^/]*$/, ''); // Remove path, keep base | ||
| if (!servers.includes(baseUrl)) { | ||
| servers.push(baseUrl); | ||
| } | ||
| }); | ||
|
|
||
| return servers.length > 0 ? servers : ['https://cloud.layer5.io']; | ||
| } |
| (dict "key" "path" "label" "Path parameters") | ||
| (dict "key" "query" "label" "Query parameters") | ||
| (dict "key" "header" "label" "Header parameters") | ||
| (dict "key" "cookie" "label" "Cookie parameters") |
| async executeRequest(operationId) { | ||
| const operationPanel = document.querySelector(`[data-operation-id="${operationId}"]`); | ||
| if (!operationPanel) { | ||
| console.error(`Operation panel not found for ${operationId}`); | ||
| return; |
| try { | ||
| // Get operation metadata from data attributes | ||
| const operation = this.getOperationMetadata(operationPanel); | ||
|
|
||
| // Build the complete URL with parameters | ||
| const url = this.buildRequestUrl(operationPanel, operation); | ||
|
|
||
| // Extract headers (including auth token if provided) | ||
| const headers = this.buildRequestHeaders(operationPanel); | ||
|
|
Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
cdd1188 to
89cd5af
Compare
…ibutes Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
89cd5af to
6df9707
Compare
Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
…d panel updates Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
…erse-tabnabbing Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
… URLs Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
…xt fields Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
Signed-off-by: Yash-Raj-5424 <myash3499@gmail.com>
|
@Yash-Raj-5424 Thank you for your contribution! Let's discuss this during the website call tomorrow at 5:30 PM IST | 7 AM CST Add it as an agenda item to the meeting minutes, if you would 🙂 |
|
@Bhumikagarggg sure. will add |
Rajesh-Nagarajan-11
left a comment
There was a problem hiding this comment.
Please consider gemini and co-pilot review and please use sistent button's and icons for theme consistency
|
Screencast from 2026-05-04 19-50-14.webm |
|
sure @Rajesh-Nagarajan-11 |
[docs] Interactive REST API Request Execution
Description
This PR adds interactive REST API querying capability to the Layer5 documentation, enabling users to execute GET requests directly from the API documentation without leaving the page.
What's New
Files Changed
docs/static/js/rest-api-executor.js- Core JavaScript module for API request executiondocs/static/scss/rest-api-interactive.scss- Styling for interactive componentsdocs/layouts/partials/rest-apis/execute-button.html- Execute button componentdocs/layouts/partials/rest-apis/server-selector.html- API server selector dropdowndocs/layouts/partials/rest-apis/auth-input.html- Bearer token input fielddocs/layouts/partials/rest-apis/url-preview.html- Live URL preview displaydocs/layouts/partials/rest-apis/parameter-inputs.html- Dynamic parameter form fieldsdocs/layouts/partials/rest-apis/viewer.html- Integrated execute section (GET endpoints only)docs/layouts/docs/rest-apis.html- Added script tag to load executor moduleHow to Test
Notes for Reviewers
Signed commits
Results: