Skip to content

feat:API robustness enhancement#3670#309

Open
devlopharsh wants to merge 4 commits intokeploy:mainfrom
devlopharsh:feat/API-robustness-enhancement#3670
Open

feat:API robustness enhancement#3670#309
devlopharsh wants to merge 4 commits intokeploy:mainfrom
devlopharsh:feat/API-robustness-enhancement#3670

Conversation

@devlopharsh
Copy link
Copy Markdown

Related Tickets & Documents

Fixes: #3670

Description

Issue : fetchAPI does not defensively handle common HTTP and network failure scenarios. As a result, failures propagate in unclear or uncontrolled ways, making them difficult to diagnose and potentially harmful to production stability.

Changes

  • Implement retry with backoff for 5xx/429 ,
  • handle API with timeout ,
  • add structured error type for consumers .

Type of Change

  • Chore (maintenance, refactoring, tooling updates)
  • Bug fix (non-breaking change that fixes an issue)
  • New feature (change that adds functionality)
  • Breaking Change (may require updates in existing code)
  • UI improvement (visual or design changes)
  • Performance improvement (optimization or efficiency enhancements)
  • Documentation update (changes to README, guides, etc.)
  • CI (updates to continuous integration workflows)
  • Revert (undo a previous commit or merge)

Testing

  • Successfully build and run the project , faced no issue .
  • Tested the done feature manually , faced no issues .

Environment and Dependencies

  • New Dependencies: NA
  • Configuration Changes: WORDPRESS_API_TIMEOUT_MS = x (x is in second)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have added corresponding tests
  • I have run the build command to ensure there are no build errors
  • My changes have been tested across relevant browsers/devices
  • For UI changes, I've included visual evidence of my changes

Signed-off-by: developharsh <harsh237hk@gmail.com>
@devlopharsh
Copy link
Copy Markdown
Author

@amaan-bhati @Achanandhi-M , please review the PR and acknowledge about the changes needed, thank you : )

@devlopharsh
Copy link
Copy Markdown
Author

@amaan-bhati , @Achanandhi-M please have are view over this

@dhananjay6561 dhananjay6561 requested a review from Copilot April 6, 2026 12:05
@dhananjay6561
Copy link
Copy Markdown
Member

Hey @devlopharsh 👋 — thanks so much for contributing to the project, really appreciate it!

Your PR looks great and has been marked for merging. Here's a quick note from the reviewer:

Adds AbortController timeout, HTTP status checking, Content-Type validation to fetchAPI().

We'll get this merged in soon. Keep the great work coming! 🚀

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

Improves robustness of the WordPress WPGraphQL client (fetchAPI) by adding request timeouts and more defensive handling of non-ideal HTTP/network responses.

Changes:

  • Add configurable request timeout using AbortController with WORDPRESS_API_TIMEOUT_MS fallback.
  • Improve error surfacing for network/timeout failures, non-2xx HTTP responses, and invalid JSON.
  • Tighten header typing and add a guard for missing API endpoint configuration.

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

Comment thread lib/api.ts
{ variables, timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS }: Record<string, any> = {}
) {
if (!API_URL) {
throw new Error("WORDPRESS_API_URL is not configured");
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

The error message here only mentions WORDPRESS_API_URL, but API_URL is also sourced from NEXT_PUBLIC_WORDPRESS_API_URL. Consider updating the message to reference both env vars and include a clear next step (e.g., set one of them to the WPGraphQL endpoint).

Suggested change
throw new Error("WORDPRESS_API_URL is not configured");
throw new Error(
"Neither WORDPRESS_API_URL nor NEXT_PUBLIC_WORDPRESS_API_URL is configured. Set one of them to your WordPress WPGraphQL endpoint."
);

Copilot uses AI. Check for mistakes.
Comment thread lib/api.ts
process.env.WORDPRESS_API_TIMEOUT_MS || "",
10
);
// can be overidden by setting the env , else the default will be used
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

Typo/grammar in this comment: "overidden" -> "overridden" (also consider removing extra spaces around punctuation for readability).

Suggested change
// can be overidden by setting the env , else the default will be used
// Can be overridden by setting the env; otherwise, the default will be used.

Copilot uses AI. Check for mistakes.
Comment thread lib/api.ts
Comment on lines +16 to +19
async function fetchAPI(
query = "",
{ variables, timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS }: Record<string, any> = {}
) {
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

PR description mentions retry/backoff for 5xx/429 and a structured error type, but this implementation currently only adds timeout + richer Error messages and does not retry or expose a typed/structured error. Either implement those behaviors here or adjust the PR description to match the actual change set.

Copilot uses AI. Check for mistakes.
Comment thread lib/api.ts
Comment on lines +53 to +64
const contentType = res.headers.get("content-type") || "";
const isJson = contentType.includes("application/json");
const rawBody = isJson ? null : await res.text();

let json: any = null;
if (isJson) {
try {
json = await res.json();
} catch (err: any) {
throw new Error(`Invalid JSON response (status ${res.status}): ${err?.message || "parse failed"}`);
}
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

If the server responds with a non-JSON Content-Type but a 2xx status, this function will currently return undefined (since json stays null) and callers will fail later with less context. Consider explicitly throwing when !isJson (or when json is null) for successful responses, including a short body snippet for diagnosis.

Copilot uses AI. Check for mistakes.
Comment thread lib/api.ts
Comment on lines +16 to +34
async function fetchAPI(
query = "",
{ variables, timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS }: Record<string, any> = {}
) {
if (!API_URL) {
throw new Error("WORDPRESS_API_URL is not configured");
}

const headers: Record<string, string> = { "Content-Type": "application/json" };

if (process.env.WORDPRESS_AUTH_REFRESH_TOKEN) {
headers[
"Authorization"
] = `Bearer ${process.env.WORDPRESS_AUTH_REFRESH_TOKEN}`;
}
// WPGraphQL Plugin must be enabled
const res = await fetch(API_URL, {
headers,
method: "POST",
body: JSON.stringify({
query,
variables,
}),
});

const json = await res.json();
if (json.errors) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);

Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

timeoutMs is accepted as any and can be overridden by callers; if it’s non-finite/<=0, setTimeout may behave unexpectedly (immediate abort / no timeout). Consider validating/coercing timeoutMs to a finite positive integer before using it, and tightening the options type to prevent accidental misuse.

Copilot uses AI. Check for mistakes.
Comment thread lib/api.ts
Comment on lines +73 to 76
if (json?.errors) {
console.error(json.errors);
throw new Error("Failed to fetch API");
throw new Error(`GraphQL errors: ${JSON.stringify(json.errors).slice(0, 500)}`);
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

This path logs full json.errors to stderr and then throws an error containing (a truncated) JSON string. That can lead to duplicate logging and may leak verbose upstream details into logs. Consider removing the console.error, or truncating/sanitizing what gets logged/thrown (and relying on the thrown error for diagnostics).

Copilot uses AI. Check for mistakes.
Comment thread lib/api.ts
Comment on lines +16 to +19
async function fetchAPI(
query = "",
{ variables, timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS }: Record<string, any> = {}
) {
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

PR checklist/description indicates corresponding tests were added, but this PR only changes lib/api.ts and the repo currently has no test script in package.json. If tests exist elsewhere, consider adding/including them here; otherwise, please update the PR testing/checklist statements to reflect what was actually done.

Copilot uses AI. Check for mistakes.
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.

[feature]: Improve fetchAPI robustness: explicit HTTP error handling, timeouts, and retry strategy

3 participants