Skip to content

fix: issues in api request viewer#1257

Open
SoulPancake wants to merge 4 commits into
mainfrom
fix/issues-in-execute-api-req-viewer
Open

fix: issues in api request viewer#1257
SoulPancake wants to merge 4 commits into
mainfrom
fix/issues-in-execute-api-req-viewer

Conversation

@SoulPancake
Copy link
Copy Markdown
Member

@SoulPancake SoulPancake commented May 11, 2026

Description

for #1254

What problem is being solved?

How is it being solved?

What changes are made to solve it?

References

Review Checklist

  • I have clicked on "allow edits by maintainers".
  • I have added documentation for new/changed functionality in this PR or in a PR to openfga.dev [Provide a link to any relevant PRs in the references section above]
  • The correct base branch is being used, if not main
  • I have added tests to validate that the change in functionality is working as expected

Summary by CodeRabbit

Release Notes

  • New Features
    • Added CURL command generation for API request snippets in both standard and streaming request viewers, enabling users to copy and execute requests directly from the documentation.

Review Change Stack

Copilot AI review requested due to automatic review settings May 11, 2026 14:45
@SoulPancake SoulPancake requested review from a team as code owners May 11, 2026 14:45
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4c9ddf96-fdc0-4c55-b661-c8f04790b9cd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR adds CURL code generation support to both standard and streaming API request viewers, and refactors the streaming viewer to propagate request metadata (method and query parameters) while removing responseField extraction in favor of printing full response objects per language.

Changes

CURL Support and Streaming Refactor

Layer / File(s) Summary
Streaming Options Interface
src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx
Streaming viewer options interface removes responseField selector and extends base request viewer options.
Non-Streaming CURL Implementation
src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx
New SupportedLanguage.CURL case generates curl commands with $FGA_API_URL, path parameters, query strings, bearer token header, JSON body, and response example comments.
Non-Streaming Language Registration
src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx
SupportedLanguage.CURL added to ExecuteApiRequestViewer default allowed languages.
Streaming Code Generator Overhaul
src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx
Streaming generator accepts method and queryParams, removes per-language responseField extraction logic, updates language-specific code to output full chunk/response objects (JavaScript logs entire chunk, Go prints unmarshaled result, .NET logs items directly), and adds CURL snippet generation for streaming.
Streaming Language Registration
src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx
SupportedLanguage.CURL added to ExecuteApiRequestStreamingViewer default allowed languages.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and generic, using non-specific language like 'issues' without conveying what problems were actually fixed or the primary change in the code. Consider using a more specific title that describes the main change, such as 'Add CURL support to API request viewers' or 'Remove responseField selector from streaming viewer', to clearly communicate the primary purpose of this changeset.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issues-in-execute-api-req-viewer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 11, 2026

PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://openfga.github.io/openfga.dev/pr-preview/pr-1257/

Built to branch gh-pages at 2026-05-11 15:50 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses the reported issues in ExecuteApiRequestViewer / ExecuteApiRequestStreamingViewer by adding a curl tab and making streaming snippet generation honor the provided HTTP method, query params, and optional body while simplifying streamed output logging.

Changes:

  • Add SupportedLanguage.CURL support for both non-streaming and streaming API executor viewers.
  • Update streaming snippet generation to respect method and queryParams, and omit body-related code when no body is provided.
  • Simplify streaming output logging across SDK snippets to print the streamed item rather than a hardcoded field/type.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}
let code = `curl -X ${method} '${url}' \\\n`;
code += ` -H 'Content-Type: application/json' \\\n`;
code += ` -H 'Authorization: Bearer $FGA_BEARER_TOKEN'`;
Comment thread src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx
code += `await foreach (var item in executor.ExecuteStreamingAsync<object, Dictionary<string, object>>(\n`;
code += ` request, "${operationName}"))\n{\n`;
code += ` Console.WriteLine(item.${field.charAt(0).toUpperCase() + field.slice(1)});`;
code += ` Console.WriteLine(item);`;
Comment on lines +271 to +294
case SupportedLanguage.CURL: {
let url = `$FGA_API_URL${path}`;
if (pathParams) {
for (const [k, v] of Object.entries(pathParams)) {
url = url.split(`{${k}}`).join(v);
}
}
if (queryParams && Object.keys(queryParams).length > 0) {
const qs = Object.entries(queryParams)
.map(([k, v]) => `${k}=${v}`)
.join('&');
url += `?${qs}`;
}
let code = `curl -X ${method} '${url}' \\\n`;
code += ` -H 'Content-Type: application/json' \\\n`;
code += ` -H 'Authorization: Bearer $FGA_BEARER_TOKEN'`;
if (body) {
code += ` \\\n -d '${JSON.stringify(body, null, 2)}'`;
}
if (responseExample) {
code += `\n\n# Response: ${responseExample}`;
}
return code;
}
}
let code = `curl -X ${method} '${url}' \\\n`;
code += ` -H 'Content-Type: application/json' \\\n`;
code += ` -H 'Authorization: Bearer $FGA_BEARER_TOKEN'`;
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx (1)

322-323: 💤 Low value

Prefer a type alias over an empty extending interface.

The eslint-disable is only needed because the body is empty. A type alias expresses the same intent without suppressing the rule, and stays correct if the parent type changes.

♻️ Proposed refactor
-// eslint-disable-next-line `@typescript-eslint/no-empty-object-type`
-interface ExecuteApiRequestStreamingViewerOpts extends ExecuteApiRequestViewerOpts {}
+type ExecuteApiRequestStreamingViewerOpts = ExecuteApiRequestViewerOpts;

Note: responseExample is inherited via this type but the streaming generator (line 326) neither destructures nor emits it. If that is intentional, consider Omit<ExecuteApiRequestViewerOpts, 'responseExample'> so callers aren't misled into passing it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx` around lines
322 - 323, Replace the empty extending interface
ExecuteApiRequestStreamingViewerOpts with a type alias to avoid disabling the
eslint rule: declare ExecuteApiRequestStreamingViewerOpts =
ExecuteApiRequestViewerOpts; also consider whether the streaming viewer actually
uses responseExample (the streaming generator around the streaming viewer code
does not destructure or emit responseExample) and if not change the alias to
Omit<ExecuteApiRequestViewerOpts, 'responseExample'> so callers aren't misled
into passing that prop.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx`:
- Around line 271-294: The curl branch in ExecuteApiRequestViewer.tsx builds
URLs and bodies without encoding or escaping: update the path param substitution
(the url mutation that does url.split(`{${k}}`).join(v)) to insert
encodeURIComponent(v) for each path value; when building the query string (the
map producing `${k}=${v}`) use encodeURIComponent for both key and value; and
make the body safe for shell by JSON.stringify(body, null, 2) and then escaping
single quotes inside that JSON (replace each ' with the shell-safe sequence
'"'"') before wrapping it in single quotes in the -d argument so the generated
curl string (the variable code) never breaks on apostrophes.
- Around line 465-485: In the SupportedLanguage.CURL branch inside
ExecuteApiRequestViewer.tsx (the CURL case building the `code` string for
method/path/url/body/responseExample), add the streaming-specific fixes: insert
`-N` (or `--no-buffer`) immediately after `curl` when building the command for
streaming endpoints, ensure any JSON body embedded in single quotes is
shell-safe by escaping single quotes (use .replace(/'/g, "'\\''") on
JSON.stringify(body, null, 2)), and emit the same `# Response:` comment using
`responseExample` as the non-streaming case so the field is not ignored;
optionally factor the duplicated CURL construction into a helper like
`buildCurlCommand({method, url, body, responseExample, streaming})` and call it
from both the non-streaming and streaming branches to keep behavior consistent.

---

Nitpick comments:
In `@src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx`:
- Around line 322-323: Replace the empty extending interface
ExecuteApiRequestStreamingViewerOpts with a type alias to avoid disabling the
eslint rule: declare ExecuteApiRequestStreamingViewerOpts =
ExecuteApiRequestViewerOpts; also consider whether the streaming viewer actually
uses responseExample (the streaming generator around the streaming viewer code
does not destructure or emit responseExample) and if not change the alias to
Omit<ExecuteApiRequestViewerOpts, 'responseExample'> so callers aren't misled
into passing that prop.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 60f03d65-850f-4e6d-81f9-f3757ec098d9

📥 Commits

Reviewing files that changed from the base of the PR and between 2108fb7 and c84a1e4.

📒 Files selected for processing (1)
  • src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx

Comment on lines +271 to +294
case SupportedLanguage.CURL: {
let url = `$FGA_API_URL${path}`;
if (pathParams) {
for (const [k, v] of Object.entries(pathParams)) {
url = url.split(`{${k}}`).join(v);
}
}
if (queryParams && Object.keys(queryParams).length > 0) {
const qs = Object.entries(queryParams)
.map(([k, v]) => `${k}=${v}`)
.join('&');
url += `?${qs}`;
}
let code = `curl -X ${method} '${url}' \\\n`;
code += ` -H 'Content-Type: application/json' \\\n`;
code += ` -H 'Authorization: Bearer $FGA_BEARER_TOKEN'`;
if (body) {
code += ` \\\n -d '${JSON.stringify(body, null, 2)}'`;
}
if (responseExample) {
code += `\n\n# Response: ${responseExample}`;
}
return code;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Generated curl commands are malformed for common inputs (no URL-encoding, unsafe single-quote body wrapping).

Three concrete defects in the new CURL branch will cause users who copy-paste the snippet to hit broken requests:

  1. Path parameters are not URL-encoded. url.split(\{${k}}`).join(v)substitutes raw values, so anyvcontaining/, :, ?, #`, space, etc. produces a malformed URL.
  2. Query parameters are not URL-encoded. ${k}=${v} will silently break for values containing &, =, #, +, or spaces.
  3. Body wrapped in single quotes will break on apostrophes. -d '${JSON.stringify(body, null, 2)}' — if any JSON string value contains a single quote (e.g. a user name like O'Brien), the shell single-quote string is terminated early and the resulting command is invalid. This is realistic for example data shown in docs.
🛠️ Proposed fix
     case SupportedLanguage.CURL: {
       let url = `$FGA_API_URL${path}`;
       if (pathParams) {
         for (const [k, v] of Object.entries(pathParams)) {
-          url = url.split(`{${k}}`).join(v);
+          url = url.split(`{${k}}`).join(encodeURIComponent(v));
         }
       }
       if (queryParams && Object.keys(queryParams).length > 0) {
         const qs = Object.entries(queryParams)
-          .map(([k, v]) => `${k}=${v}`)
+          .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
           .join('&');
         url += `?${qs}`;
       }
       let code = `curl -X ${method} '${url}' \\\n`;
       code += `  -H 'Content-Type: application/json' \\\n`;
       code += `  -H 'Authorization: Bearer $FGA_BEARER_TOKEN'`;
       if (body) {
-        code += ` \\\n  -d '${JSON.stringify(body, null, 2)}'`;
+        // Escape single quotes so the shell-quoted -d body survives apostrophes in example data.
+        const json = JSON.stringify(body, null, 2).replace(/'/g, `'\\''`);
+        code += ` \\\n  -d '${json}'`;
       }
       if (responseExample) {
         code += `\n\n# Response: ${responseExample}`;
       }
       return code;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case SupportedLanguage.CURL: {
let url = `$FGA_API_URL${path}`;
if (pathParams) {
for (const [k, v] of Object.entries(pathParams)) {
url = url.split(`{${k}}`).join(v);
}
}
if (queryParams && Object.keys(queryParams).length > 0) {
const qs = Object.entries(queryParams)
.map(([k, v]) => `${k}=${v}`)
.join('&');
url += `?${qs}`;
}
let code = `curl -X ${method} '${url}' \\\n`;
code += ` -H 'Content-Type: application/json' \\\n`;
code += ` -H 'Authorization: Bearer $FGA_BEARER_TOKEN'`;
if (body) {
code += ` \\\n -d '${JSON.stringify(body, null, 2)}'`;
}
if (responseExample) {
code += `\n\n# Response: ${responseExample}`;
}
return code;
}
case SupportedLanguage.CURL: {
let url = `$FGA_API_URL${path}`;
if (pathParams) {
for (const [k, v] of Object.entries(pathParams)) {
url = url.split(`{${k}}`).join(encodeURIComponent(v));
}
}
if (queryParams && Object.keys(queryParams).length > 0) {
const qs = Object.entries(queryParams)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&');
url += `?${qs}`;
}
let code = `curl -X ${method} '${url}' \\\n`;
code += ` -H 'Content-Type: application/json' \\\n`;
code += ` -H 'Authorization: Bearer $FGA_BEARER_TOKEN'`;
if (body) {
// Escape single quotes so the shell-quoted -d body survives apostrophes in example data.
const json = JSON.stringify(body, null, 2).replace(/'/g, `'\\''`);
code += ` \\\n -d '${json}'`;
}
if (responseExample) {
code += `\n\n# Response: ${responseExample}`;
}
return code;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx` around lines
271 - 294, The curl branch in ExecuteApiRequestViewer.tsx builds URLs and bodies
without encoding or escaping: update the path param substitution (the url
mutation that does url.split(`{${k}}`).join(v)) to insert encodeURIComponent(v)
for each path value; when building the query string (the map producing
`${k}=${v}`) use encodeURIComponent for both key and value; and make the body
safe for shell by JSON.stringify(body, null, 2) and then escaping single quotes
inside that JSON (replace each ' with the shell-safe sequence '"'"') before
wrapping it in single quotes in the -d argument so the generated curl string
(the variable code) never breaks on apostrophes.

Comment on lines +465 to +485
case SupportedLanguage.CURL: {
let url = `$FGA_API_URL${path}`;
if (pathParams) {
for (const [k, v] of Object.entries(pathParams)) {
url = url.split(`{${k}}`).join(v);
}
}
if (queryParams && Object.keys(queryParams).length > 0) {
const qs = Object.entries(queryParams)
.map(([k, v]) => `${k}=${v}`)
.join('&');
url += `?${qs}`;
}
let code = `curl -X ${method} '${url}' \\\n`;
code += ` -H 'Content-Type: application/json' \\\n`;
code += ` -H 'Authorization: Bearer $FGA_BEARER_TOKEN'`;
if (body) {
code += ` \\\n -d '${JSON.stringify(body, null, 2)}'`;
}
return code;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

curl streaming response no-buffer flag -N documentation

💡 Result:

The -N or --no-buffer flag in curl disables output buffering, enabling real-time streaming of responses as data arrives, rather than in buffered chunks. This is particularly useful for streaming responses like Server-Sent Events (SSE), live updates, or piping to other commands without delays. From the official curl manual: "-N, --no-buffer: Disables the buffering of the output stream. In normal work situations, curl will use a standard buffered output stream that will have the effect that it will output the data in chunks, not necessarily exactly when the data arrives. Using this option will disable that buffering. Note that this is the negated option name documented. You can thus use --buffer to enforce the buffering."[1][2][3][4] Example usage for streaming: curl -N https://example.com/stream-endpoint[5][6] This flag affects stdout output and is key for progressive display or processing of long-running responses.[7][8]

Citations:


🏁 Script executed:

# First, locate and read the file
fd -t f "ExecuteApiRequestViewer.tsx" | head -5

Repository: openfga/openfga.dev

Length of output: 125


🏁 Script executed:

# Get file size to determine how to read it
wc -l "src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx"

Repository: openfga/openfga.dev

Length of output: 129


🏁 Script executed:

# Read the relevant sections: lines 260-300 (non-streaming CURL), 315-330, and 460-490 (streaming CURL)
sed -n '260,300p; 315,330p; 460,490p' "src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx" -n

Repository: openfga/openfga.dev

Length of output: 3216


🏁 Script executed:

# Verify the full context of both functions to understand scope better
sed -n '245,310p; 455,500p' "src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx"

Repository: openfga/openfga.dev

Length of output: 3751


🏁 Script executed:

# Check for any other streaming-related CURL handling or configuration
rg -n "streaming|CURL|curl|no-buffer|-N" "src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx" | head -20

Repository: openfga/openfga.dev

Length of output: 609


Add -N flag and fix quote escaping in streaming CURL, plus handle missing responseExample comment.

The streaming CURL output has two issues:

  1. Missing -N / --no-buffer flag. Streaming endpoints require this flag to disable output buffering, otherwise users copying the command won't observe streaming behavior in real-time. Add -N immediately after curl.

  2. Inconsistent responseExample handling. The non-streaming CURL case (lines 271–304) includes if (responseExample) to emit a # Response: comment, but the streaming case omits this block entirely. This leaves the responseExample field silently unused in the streaming function's public API.

Additionally, both cases need quote escaping for the JSON body (use .replace(/'/g, "'\\''") when embedding in single-quoted shell strings), consistent with best practices for shell safety.

🛠️ Proposed fix
     case SupportedLanguage.CURL: {
       let url = `$FGA_API_URL${path}`;
       if (pathParams) {
         for (const [k, v] of Object.entries(pathParams)) {
           url = url.split(`{${k}}`).join(v);
         }
       }
       if (queryParams && Object.keys(queryParams).length > 0) {
         const qs = Object.entries(queryParams)
           .map(([k, v]) => `${k}=${v}`)
           .join('&');
         url += `?${qs}`;
       }
-      let code = `curl -X ${method} '${url}' \\\n`;
+      let code = `curl -N -X ${method} '${url}' \\\n`;
        code += `  -H 'Content-Type: application/json' \\\n`;
        code += `  -H 'Authorization: Bearer $FGA_BEARER_TOKEN'`;
        if (body) {
-        code += ` \\\n  -d '${JSON.stringify(body, null, 2)}'`;
+        const json = JSON.stringify(body, null, 2).replace(/'/g, `'\\''`);
+        code += ` \\\n  -d '${json}'`;
+      }
+      if (responseExample) {
+        code += `\n\n# Response: ${responseExample}`;
        }
        return code;
      }

Consider extracting the duplicated CURL builder logic (lines 271–304 and 465–490 are nearly identical) into a helper function that accepts a streaming: boolean parameter. This would eliminate ~20 lines of duplication and ensure encoding/streaming fixes are applied consistently in one place.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Docs/SnippetViewer/ExecuteApiRequestViewer.tsx` around lines
465 - 485, In the SupportedLanguage.CURL branch inside
ExecuteApiRequestViewer.tsx (the CURL case building the `code` string for
method/path/url/body/responseExample), add the streaming-specific fixes: insert
`-N` (or `--no-buffer`) immediately after `curl` when building the command for
streaming endpoints, ensure any JSON body embedded in single quotes is
shell-safe by escaping single quotes (use .replace(/'/g, "'\\''") on
JSON.stringify(body, null, 2)), and emit the same `# Response:` comment using
`responseExample` as the non-streaming case so the field is not ignored;
optionally factor the duplicated CURL construction into a helper like
`buildCurlCommand({method, url, body, responseExample, streaming})` and call it
from both the non-streaming and streaming branches to keep behavior consistent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants