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
80 changes: 64 additions & 16 deletions lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,78 @@ export const dynamic = 'force-dynamic';

const API_URL = process.env.WORDPRESS_API_URL || process.env.NEXT_PUBLIC_WORDPRESS_API_URL

async function fetchAPI(query = "", { variables }: Record<string, any> = {}) {
const headers = { "Content-Type": "application/json" };
const DEFAULT_TIMEOUT_MS = 10000;
const envTimeoutMs = Number.parseInt(
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.
const DEFAULT_REQUEST_TIMEOUT_MS = Number.isFinite(envTimeoutMs)
? envTimeoutMs
: DEFAULT_TIMEOUT_MS;

async function fetchAPI(
query = "",
{ variables, timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS }: Record<string, any> = {}
) {
Comment on lines +16 to +19
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 on lines +16 to +19
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.
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.
}

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);

Comment on lines +16 to +34
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.
let res: Response;
try {
res = await fetch(API_URL, {
headers,
method: "POST",
body: JSON.stringify({
query,
variables,
}),
signal: controller.signal,
});
} catch (err: any) {
const reason = err?.name === "AbortError" ? "Request timed out" : "Network error";
throw new Error(`${reason}: ${err?.message || "unknown"}`);
} finally {
clearTimeout(timeoutId);
}

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"}`);
}
}
Comment on lines +53 to +64
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.

if (!res.ok) {
const bodySnippet = isJson ? JSON.stringify(json) : rawBody;
throw new Error(
`HTTP ${res.status} ${res.statusText}: ${bodySnippet?.slice(0, 500) || "no body"}`
);
}

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)}`);
}
Comment on lines +73 to 76
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.
return json.data;
return json?.data;
}

export async function getPreviewPost(id, idType = "DATABASE_ID") {
Expand Down Expand Up @@ -844,4 +892,4 @@ export async function getAllPostsForSearch(preview = false) {
);

return data?.posts?.edges || [];
}
}