Skip to content

Conversation

sunilsabatp
Copy link
Contributor

@sunilsabatp sunilsabatp commented Mar 20, 2025

Branch Name Validation Changes:

  • Removed the 'api-refactor' branch prefix from the validation pattern

API Refactoring Work:

  • Utilize the useServerApi() hook to fetch project and plant location data
  • Added Content-Type header handling for requests with a body
  • Set 'Content-Type' to 'application/json' for 'POST', 'PUT', and 'DELETE' requests
  • Made the payload a required parameter for POST and PUT methods
  • Restricted the 'data' type from 'any' to more specific types ('Record<string, string>') for better type safety
  • Performed minor renaming for better clarity

Bug Fixes:

  • Fixed an issue to allow passing additional headers in postApiAuthenticated API
  • Ensured Content-Type is only set for requests with a request body
  • Ensured'x-accept-versions'header is only added if a version is provided

Code Cleanup:

  • Removed unused deleteApi function and middleware
  • Performed minor refactoring to improve code readability

NOTE : For future versioning, we could use an environment variable.

…d set Content-Type only for requests with a request body.
…body

- set 'Content-Type' to 'application/json' for 'POST', 'PUT', and 'DELETE' requests.
- ensure 'x-accept-versions' is only added if a version is provided.
- minor refactoring for improved readability.
- make payload a required parameter for POST and PUT method.
- remove unused deleteApi  function and middleware.
- options -> config
- requestOptions -> requestConfig
Copy link

vercel bot commented Mar 20, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
planet-webapp-multi-tenancy-setup ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 30, 2025 1:14pm
2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
planet-webapp ⬜️ Ignored (Inspect) Mar 30, 2025 1:14pm
planet-webapp-temp ⬜️ Ignored (Inspect) Mar 30, 2025 1:14pm

Copy link
Contributor

coderabbitai bot commented Mar 20, 2025

Walkthrough

The changes refactor API interactions across multiple components by replacing the old getRequest and useServerApi functions with the new useApi hook. Several components and pages update their API call logic—simplifying parameter passing and removing outdated tenant configuration. The apiClient function has been restructured with stricter typing and streamlined header and URL handling. Error handling remains unchanged while function signatures are modified to match the new API interface.

Changes

File(s) Change Summary
pages/sites/[slug]/[locale]/all.tsx, src/features/projectsV2/ProjectDetails/index.tsx, src/features/projectsV2/ProjectsContext.tsx Updated API fetching logic: replaced getRequest with getApi and removed legacy tenant configurations. Function signatures were modified (e.g., removal of the locale parameter).
src/features/user/DonationReceipt/DonationReceiptUnauthenticated.tsx, src/features/user/DonationReceipt/DonationReceiptWrapper.tsx, src/features/user/DonationReceipt/DonationReceipts.tsx, src/features/user/DonationReceipt/DonorContactManagement.tsx Replaced import and usage of useServerApi with useApi for API calls; internal API method calls updated accordingly.
src/hooks/useApi.ts New hook useApi introduced to centralize API requests, with methods for various HTTP operations and enhanced error handling.
src/utils/apiRequests/apiClient.ts Expanded and updated the RequestOptions type with properties like method, url, queryParams, additionalHeaders, and authRequired. Simplified URL construction and header management; changed data type from any to Record<string, string>.

Sequence Diagram(s)

sequenceDiagram
    participant C as Component
    participant UA as useApi Hook
    participant AC as apiClient

    C->>UA: Invoke API function (e.g., getApi)
    UA->>AC: Call apiClient with method, url, headers, etc.
    AC-->>UA: Return API response or error
    UA-->>C: Return data to component
Loading

Possibly related PRs

Suggested labels

PR: reviewed-approved

Suggested reviewers

  • mohitb35

Poem

I'm a nimble rabbit, skipping over code,
Out with the old ways on our API road.
useApi now leads the joyful chase,
Cleaner code and structure in every place.
With every hop, our systems align—
A bouncy celebration in each design!

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
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: 1

🔭 Outside diff range comments (1)
pages/sites/[slug]/[locale]/all.tsx (1)

88-101: 🛠️ Refactor suggestion

Consider updating the remaining getRequest call.

The loadTreesDonated function still uses the old getRequest method, while other similar functions have been updated to use getApi.

async function loadTreesDonated() {
  try {
-    const newTreesDonated = await getRequest<TreesDonated>({
-      tenant: pageProps.tenantConfig.id,
-      url: `${process.env.WEBHOOK_URL}/platform/total-tree-count`,
-    });
+    const newTreesDonated = await getApi<TreesDonated>(
+      `${process.env.WEBHOOK_URL}/platform/total-tree-count`
+    );
    setTreesDonated(newTreesDonated);
  } catch (err) {
    setErrors(handleError(err as APIError));
  }
}
🧹 Nitpick comments (2)
src/utils/apiRequests/apiClient.ts (2)

25-25: Remove unnecessary empty fallback in spread operator.

The empty fallback in the spread operator is unnecessary and can be simplified.

const headers: Record<string, string> = {
-  ...(config.additionalHeaders || {}),
+  ...(config.additionalHeaders || {})
};
🧰 Tools
🪛 GitHub Check: CodeFactor

[notice] 25-25: src/utils/apiRequests/apiClient.ts#L25
Empty fallbacks in spreads are unnecessary. (eslint-plugin-unicorn/no-useless-fallback-in-spread)


30-34: Possible issue with body being included in GET requests.

When using the ternary operation to conditionally include the body, ensure that GET requests don't include a body, as this may cause issues with some servers.

const response = await fetch(fullUrl, {
  method: config.method,
  headers,
-  body: ['POST', 'PUT'].includes(config.method)
-    ? JSON.stringify(config.data)
-    : undefined,
+  ...((['POST', 'PUT', 'DELETE'].includes(config.method) && config.data) 
+    ? { body: JSON.stringify(config.data) } 
+    : {})
});
🧰 Tools
🪛 GitHub Check: CodeFactor

[notice] 32-32: src/utils/apiRequests/apiClient.ts#L32
"body" is not allowed when method is "GET". (eslint-plugin-unicorn/no-invalid-fetch-options)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ad500c and e31104e.

⛔ Files ignored due to path filters (1)
  • package.json is excluded by !**/*.json
📒 Files selected for processing (5)
  • pages/sites/[slug]/[locale]/all.tsx (4 hunks)
  • src/features/projectsV2/ProjectDetails/index.tsx (3 hunks)
  • src/features/projectsV2/ProjectsContext.tsx (4 hunks)
  • src/hooks/useServerApi.ts (5 hunks)
  • src/utils/apiRequests/apiClient.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
src/features/projectsV2/ProjectDetails/index.tsx (2)
src/hooks/useServerApi.ts (1) (1)
  • useServerApi (83-236)
src/features/common/types/plantLocation.d.ts (1) (1)
  • PlantLocation (66-69)
src/features/projectsV2/ProjectsContext.tsx (1)
src/hooks/useServerApi.ts (1) (1)
  • useServerApi (83-236)
🪛 Biome (1.9.4)
src/hooks/useServerApi.ts

[error] 185-185: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 193-193: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 200-200: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 207-207: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🪛 GitHub Check: CodeFactor
src/utils/apiRequests/apiClient.ts

[notice] 25-25: src/utils/apiRequests/apiClient.ts#L25
Empty fallbacks in spreads are unnecessary. (eslint-plugin-unicorn/no-useless-fallback-in-spread)


[notice] 32-32: src/utils/apiRequests/apiClient.ts#L32
"body" is not allowed when method is "GET". (eslint-plugin-unicorn/no-invalid-fetch-options)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: ESLint on Ubuntu
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (27)
pages/sites/[slug]/[locale]/all.tsx (4)

30-30: Good: Added the useServerApi hook.

This new import introduces the standardized API interaction method which is being used consistently across the codebase.


44-44: Good: Extracted getApi from the hook.

Using destructuring to extract the needed method from the hook is a clean approach.


55-57: Improved API call implementation.

The code has been simplified by replacing the getRequest function with getApi. This change removes the need to explicitly pass tenant information as it's now handled internally by the useServerApi hook.


73-75: Consistent use of getApi for tenant score.

This change aligns with the standardization pattern being applied across the codebase.

src/features/projectsV2/ProjectsContext.tsx (4)

30-30: Good: Added the useServerApi hook.

This new import introduces the standardized API interaction method which is being used consistently across the codebase.


115-115: Good: Extracted getApi from the hook.

Using destructuring to extract the needed method from the hook is a clean approach.


135-135: Good: Added safety check for properties.purpose.

The optional chaining operator (?.) provides a safeguard against potential null/undefined errors when accessing the purpose property.


205-212: Improved API call implementation.

The change from getRequest to getApi standardizes the API interaction pattern. Using proper TypeScript generics for both the response type and query parameters provides better type safety.

src/features/projectsV2/ProjectDetails/index.tsx (6)

29-29: Good: Added the useServerApi hook.

This new import introduces the standardized API interaction method which is being used consistently across the codebase.


56-56: Good: Extracted getApi from the hook.

Using destructuring to extract the needed method from the hook is a clean approach.


60-60: Good: Simplified function signature.

Removing the locale parameter from loadProject function is appropriate since the locale is now handled internally by the useServerApi hook.


64-70: Improved API call implementation with proper typing.

The use of TypeScript generics with getApi<ExtendedProject, Record<string, string>> provides better type safety for both the response and query parameters.


96-96: Code simplification: Removed locale parameter.

Removed the locale parameter from the function call since it's no longer needed in the updated implementation.


103-109: Good: Added version parameter to API call.

The use of a specific version ('1.0.4') in the API call is a good practice for API versioning, ensuring compatibility with specific API endpoints.

src/utils/apiRequests/apiClient.ts (3)

7-7: Improved type safety for the data property.

Replacing any with Record<string, string> provides better type safety by ensuring that the data object has string keys and string values.


13-15: Simplified apiClient function signature.

The function has been streamlined to directly use the request configuration without middleware processing.


17-22: Simplified URL construction.

The URL construction has been simplified by removing checks for the API endpoint and directly using the provided URL.

src/hooks/useServerApi.ts (10)

79-79: Good addition of next-intl's useLocale hook

This change better aligns with modern internationalization practices by leveraging the next-intl library, which provides more robust locale management than using localStorage.


86-86: Improved locale handling

Using the useLocale hook provides more reliable locale detection compared to potentially stale localStorage values, ensuring consistent internationalization throughout the application.


101-102: Enhanced flexibility with additionalHeaders parameter

Adding additionalHeaders to the RequestOptions makes the API more versatile by allowing consumers to pass custom headers when needed.


107-111: Improved header management

The updated header initialization properly uses the locale from next-intl and correctly spreads additionalHeaders when provided.


113-119: Better header organization with conditional logic

The implementation now properly:

  1. Only adds version headers when a version is specified
  2. Sets Content-Type header only for methods that send a body (POST, PUT, DELETE)

This is a good improvement in header management.


133-137: Improved error handling for missing API_ENDPOINT

This defensive programming approach fails fast with a clear error message when a required environment variable is missing, preventing subtle runtime issues.


172-176: Enhanced type safety for postApiAuthenticated

Making the payload required and additionalHeaders optional improves type safety and makes the API contract clearer.

🧰 Tools
🪛 Biome (1.9.4)

[error] 172-172: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


190-190: Better parameter naming and flexibility

Changing from payload to queryParams and adding the version parameter improves clarity and flexibility of the API.


219-225: Simplified deleteApiAuthenticated signature

Removing the payload parameter from the deleteApiAuthenticated method aligns with REST conventions where DELETE operations typically don't include a request body.


227-236: Comprehensive API surface

The hook exports a complete set of methods for interacting with the API, covering all common HTTP methods with both authenticated and unauthenticated variants.

…ndling

- replaced unnecessary spread operator for additionalHeaders with ?? {} to avoid empty object spreading.
- used a spread operator { ...(condition ? { body: value } : {}) } for setting body, ensuring it is completely omitted for unsupported methods.
Copy link
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: 0

🧹 Nitpick comments (1)
src/utils/apiRequests/apiClient.ts (1)

7-7: Consider using a more flexible typing for data property

While changing from any to Record<string, string> improves type safety, it might be too restrictive for API requests that need to send numbers, booleans, arrays, or nested objects.

- data?: Record<string, string>;
+ data?: Record<string, unknown>;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e31104e and c7d33cf.

📒 Files selected for processing (1)
  • src/utils/apiRequests/apiClient.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: ESLint on Ubuntu
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
src/utils/apiRequests/apiClient.ts (4)

13-14: Simplification of function signature is a good improvement

Removing the middleware parameter simplifies the API client. This change makes the code more maintainable and easier to understand.


24-24: Good use of nullish coalescing operator

The use of ?? for default headers is a clean, modern approach.


28-32: Clean implementation of conditional request body

The conditional spread operator pattern is well-applied to include the request body only for POST and PUT methods. This is a good practice that improves code clarity.


21-21:

❓ Verification inconclusive

Verify URL construction behavior across the application

The URL construction has been simplified, removing the previous checks for API_ENDPOINT environment variable. Ensure this change doesn't affect any environments where the base URL was configured differently.


🏁 Script executed:

#!/bin/bash
# Search for any references to API_ENDPOINT that might be affected
rg "API_ENDPOINT" --type typescript

Length of output: 70


Action Required: Validate API Endpoint URL Configuration

It appears that the initial command using --type typescript produced an error. To ensure that removing the API_ENDPOINT checks doesn’t affect environments with a custom-configured base URL, please run the revised script below. This script uses a glob pattern over all TypeScript files to search for any references to API_ENDPOINT:

After running this command, please verify if any instances of API_ENDPOINT appear that might be impacted by this change.


🏁 Script executed:

#!/bin/bash
# Search for any references to API_ENDPOINT in TypeScript files using glob patterns
rg "API_ENDPOINT" --glob "*.ts"

Length of output: 1656


API Endpoint Configuration Consistency – Please Verify Environment Settings

The changes in src/utils/apiRequests/apiClient.ts now construct the URL solely from config.url, removing checks for process.env.API_ENDPOINT. However, our search shows that several other parts of the codebase (e.g., in src/utils/apiRequests/api.ts, src/hooks/useServerApi.ts, and others) still depend on process.env.API_ENDPOINT. Please ensure that:

  • Environment Consistency: The new config.url value is appropriately configured for all environments, and its usage in apiClient.ts is aligned with how API endpoints are handled elsewhere.
  • Configuration Separation: The coexistence of config.url and process.env.API_ENDPOINT is intentional. Review if this split in configuration sources might lead to inconsistencies or unexpected behavior in different deployment setups.
  • Documentation & Testing: Update any relevant documentation and perform end-to-end tests to guarantee that URL construction in all modules (both in apiClient.ts and in remaining references) produces the correct results.

Copy link
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: 0

🧹 Nitpick comments (2)
src/hooks/useServerApi.ts (2)

110-110: Merging user-provided headers last allows overriding default headers.
If you want to prevent important headers like Authorization or tenant-key from being overwritten, consider filtering keys out of additionalHeaders before merging.


113-119: Minor nitpick on version assignment and content type logic.
Currently, the code sets 'x-accept-versions' = version ? version : '1.0.3' inside if (version) { ... }, which never uses '1.0.3' unless version is a falsy value but still meets the if (version) condition. You might simplify by removing the if block and using the nullish coalescing operator:

-    if (version) {
-      headers['x-accept-versions'] = version ? version : '1.0.3';
-    }
+    headers['x-accept-versions'] = version ?? '1.0.3';
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7d33cf and 3e53aa1.

📒 Files selected for processing (1)
  • src/hooks/useServerApi.ts (6 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
src/hooks/useServerApi.ts (2)
src/utils/apiRequests/apiClient.ts (1) (1)
  • RequestOptions (4-11)
src/utils/apiRequests/impersonation.tsx (1) (1)
  • ImpersonationData (1-4)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: ESLint on Ubuntu
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (16)
src/hooks/useServerApi.ts (16)

79-79: Importing the next-intl useLocale hook is a welcome improvement.
This will provide a more robust and standardized mechanism for retrieving the current locale.


86-86: Good use of the useLocale hook.
Retrieving the locale within the hook ensures consistent and dynamic localization across API requests.


101-102: Nice addition of additionalHeaders to the request options.
This extension point helps make the API client more flexible for future customization.


107-107: Ensuring x-locale is set from locale
This effectively aligns with the localization strategy. Just double-check with your backend team that they accept this header for language negotiation.


131-131: Good call folding impersonation headers into a final header object.
This centralizes the header manipulation and keeps the call site clean.


133-137: Fail fast for missing API_ENDPOINT.
Throwing an error early here is preferable to silent failures or unclear error states later on.


139-139: Constructing the final URL with isAbsoluteUrl check.
Allows flexible usage of full remote endpoints or paths relative to API_ENDPOINT. Nicely done.


147-147: Passing finalHeader as additionalHeaders
Keeps consistency with the RequestOptions interface and integrates impersonation logic seamlessly.


158-161: Using Record<string, string> instead of {}
This aligns with the previous lint guidance and clarifies the payload’s structure.


175-181: postApiAuthenticated updated to type payload and accept custom headers.
This ensures stricter typing for request payload and more flexibility for specialized headers.


189-189: Forwarding additionalHeaders
Consistently merges the custom headers in the API call—maintains the improved design.


191-197: getApi method signature improvements
Switching from generic {} to Record<string, string> reflects better type safety for query params.

Also applies to: 199-199


202-207: postApi method simplified to typed payload
Ensures uniform method signatures and consistent use of typed objects—nice improvement.


212-217: putApi method typed similarly for clarity and consistency
Good to see uniform usage of Record<string, string> for request payload types.


222-227: putApiAuthenticated method matches the typed approach
This matches the same pattern for authenticated calls—keeps everything standard.


237-237: deleteApiAuthenticated no longer accepts a payload
Removing the unused payload parameter for DELETE calls prevents confusion and aligns with typical REST usage.

…equestConfig → options) to make it clearer and more concise.
- updated getApiAuthenticated, getApi, and deleteApiAuthenticated to use stricter type constraints.
-removed unnecessary default payload initialization in postApiAuthenticated, postApi, and putApi.
Copy link
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: 1

🧹 Nitpick comments (3)
src/hooks/useApi.ts (2)

93-160: Consider optimizing error handling in callApi.

While the logic is good, if the backend returns invalid JSON on an error response, err instanceof APIError is appropriate, yet additional guards or fallback message handling might be beneficial for unexpected payload formats.


161-321: Reduce duplication in similar API methods.

All helper methods (getApi, postApi, etc.) follow a very similar pattern. You could unify them by passing an authRequired flag and other method-specific parameters to a single function, reducing repetitive code.

src/utils/apiRequests/apiClient.ts (1)

84-128: Handle unexpected JSON parsing errors gracefully.

Returning true for a 204 is sensible, but consider handling the case where the response body isn’t valid JSON on non-2xx status codes. For example, an error page or HTML response could cause await response.json() to fail.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12ee334 and 6cacdd5.

📒 Files selected for processing (5)
  • src/features/projectsV2/ProjectDetails/index.tsx (4 hunks)
  • src/features/projectsV2/ProjectsContext.tsx (4 hunks)
  • src/features/user/DonationReceipt/DonationReceiptWrapper.tsx (4 hunks)
  • src/hooks/useApi.ts (1 hunks)
  • src/utils/apiRequests/apiClient.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/features/projectsV2/ProjectsContext.tsx
  • src/features/user/DonationReceipt/DonationReceiptWrapper.tsx
  • src/features/projectsV2/ProjectDetails/index.tsx
🧰 Additional context used
🧬 Code Definitions (1)
src/hooks/useApi.ts (1)
src/utils/apiRequests/apiClient.ts (1)
  • RequestOptions (4-38)
🪛 Biome (1.9.4)
src/hooks/useApi.ts

[error] 91-91: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
src/hooks/useApi.ts (1)

1-66: Great documentation coverage.

These introductory doc comments provide thorough usage examples, dependencies, and helpful references, which make onboarding to this hook significantly easier.

src/utils/apiRequests/apiClient.ts (2)

4-38: Type definition aligns well with strict request semantics.

The union type for method-specific payload enforcement is a clear way to ensure POST and PUT always have data. Nicely done!


50-53: Well-structured URL check.

isAbsoluteUrl is concise and properly tested against both HTTP and HTTPS patterns.

Comment on lines 83 to 92
type ApiConfig<
P extends Record<string, unknown>,
M extends HttpMethod = 'GET' | 'DELETE'
> = {
queryParams?: Record<string, string>;
impersonationData?: ImpersonationData;
additionalHeaders?: Record<string, string>;
version?: string;
} & (M extends 'POST' | 'PUT' ? { payload: P } : {});

Copy link
Contributor

@coderabbitai coderabbitai bot Mar 28, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refine the empty type in the union.

When specifying : {}, prefer an explicit shape or Record<string, never> to avoid confusion with banned {} (which means “any non-nullable value”). This helps keep types more precise and avoids linter warnings.

-type ApiConfig<
-  P extends Record<string, unknown>,
-  M extends HttpMethod = 'GET' | 'DELETE'
-> = {
-  ...
-} & (M extends 'POST' | 'PUT' ? { payload: P } : {});
+type ApiConfig<
+  P extends Record<string, unknown>,
+  M extends HttpMethod = 'GET' | 'DELETE'
+> = {
+  ...
+} & (M extends 'POST' | 'PUT' ? { payload: P } : Record<string, never>);
📝 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
type ApiConfig<
P extends Record<string, unknown>,
M extends HttpMethod = 'GET' | 'DELETE'
> = {
queryParams?: Record<string, string>;
impersonationData?: ImpersonationData;
additionalHeaders?: Record<string, string>;
version?: string;
} & (M extends 'POST' | 'PUT' ? { payload: P } : {});
type ApiConfig<
P extends Record<string, unknown>,
M extends HttpMethod = 'GET' | 'DELETE'
> = {
queryParams?: Record<string, string>;
impersonationData?: ImpersonationData;
additionalHeaders?: Record<string, string>;
version?: string;
} & (M extends 'POST' | 'PUT' ? { payload: P } : Record<string, never>);
🧰 Tools
🪛 Biome (1.9.4)

[error] 91-91: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

Copy link
Contributor Author

@sunilsabatp sunilsabatp Mar 30, 2025

Choose a reason for hiding this comment

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

Updated the type to Record<string, unknown>

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

@sunilsabatp Thanks for updating the type. I notice you chose Record<string, unknown> instead of the suggested Record<string, never>.

While both avoid the banned {} type, there's a subtle difference: Record<string, never> represents a truly empty object (cannot have properties), whereas Record<string, unknown> allows any string keys with unknown values.

The original intent was likely to ensure GET/DELETE methods don't have a payload property. If you want to strictly enforce this, Record<string, never> would be more appropriate. However, if you're intentionally allowing additional properties for flexibility, your choice of Record<string, unknown> works too.


🏁 Script executed:

#!/bin/bash
# Check the current implementation in the file
grep -A 10 "type ApiConfig" src/hooks/useApi.ts

Length of output: 403


@sunilsabatp I've confirmed your implementation using Record<string, unknown> in the conditional type. This change successfully addresses the linter warning about the banned {} type.

Just for your awareness: with Record<string, unknown>, GET/DELETE methods can technically still accept additional properties (including a payload) with values of any type. If you intended to strictly prohibit additional properties for those methods, Record<string, never> would have been more restrictive. However, your implementation works fine and might offer more flexibility if needed.


✏️ Learnings added
Learnt from: sunilsabatp
PR: Plant-for-the-Planet-org/planet-webapp#2455
File: src/hooks/useApi.ts:0-0
Timestamp: 2025-03-30T13:17:53.053Z
Learning: For conditional types in TypeScript that represent empty objects, `Record<string, never>` is preferred over `{}` to avoid linter warnings about banned types. `Record<string, never>` represents a truly empty object that cannot have properties, while `Record<string, unknown>` allows arbitrary properties with unknown values.

Learnt from: sunilsabatp
PR: Plant-for-the-Planet-org/planet-webapp#2455
File: src/hooks/useApi.ts:0-0
Timestamp: 2025-03-30T13:17:53.053Z
Learning: For conditional types in TypeScript that represent empty objects, `Record<string, never>` is preferred over `{}` to avoid linter warnings about banned types. `Record<string, never>` represents a truly empty object that cannot have properties, while `Record<string, unknown>` allows arbitrary properties with unknown values.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

…adability.

-Explicitly used Record<string, unknown> for ApiConfig, ensuring a more consistent structure.
-Improved readability of requestOptions, making debugging easier.
Copy link
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: 0

🧹 Nitpick comments (4)
src/hooks/useApi.ts (4)

83-92: Refine the union type for non-POST/PUT methods.

Currently, the type (M extends 'POST' | 'PUT' ? { payload: P } : Record<string, unknown>) broadens the shape for GET/DELETE calls to Record<string, unknown>. Consider opting for a stricter type (e.g., Record<string, never>) to enforce that GET/DELETE calls cannot accidentally contain payloads, leading to more precise type checks.

-type ApiConfig<
-  P extends Record<string, unknown>,
-  M extends HttpMethod = 'GET' | 'DELETE'
-> = {
-  queryParams?: Record<string, string>;
-  ...
-} & (M extends 'POST' | 'PUT' ? { payload: P } : Record<string, unknown>);
+type ApiConfig<
+  P extends Record<string, unknown>,
+  M extends HttpMethod = 'GET' | 'DELETE'
+> = {
+  queryParams?: Record<string, string>;
+  ...
+} & (M extends 'POST' | 'PUT' ? { payload: P } : Record<string, never>);

93-148: Centralized error handling is commendable but consider additional logging or retry flow.

The callApi function cleanly focuses on critical error cases (APIError and ClientError). Consider adding optional hooks for retry logic or more detailed logging (e.g., request ID or correlation ID) to aid debugging, especially in production environments.


135-137: Consolidate data assignment logic for all methods.

You conditionally include data for POST/PUT only. If you anticipate future expansions (e.g., allowing bodies on DELETE requests), you might unify or handle them consistently to reduce repeated conditional logic. For now, it’s acceptable, but keep this in mind if expansions occur.


311-320: Consider a more unified approach or an exposed object.

Returning all methods in a single object is convenient, but consider grouping them (e.g., returning an object keyed by method type). This remains optional—your current design is perfectly usable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6cacdd5 and f329ed5.

📒 Files selected for processing (1)
  • src/hooks/useApi.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
src/hooks/useApi.ts (1)
src/utils/apiRequests/apiClient.ts (1)
  • RequestOptions (4-38)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: ESLint on Ubuntu
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
src/hooks/useApi.ts (3)

1-66: Well-documented introduction and usage summary.

The JSDoc comments covering the purpose, dependencies, and usage are thorough and will be helpful for onboarding and maintenance. Great work keeping the documentation succinct yet comprehensive.


197-238: Well-organized method wrappers for GET and POST.

Splitting out getApi, postApi, and their authenticated versions is clear and consistent with the rest of the file. This code is easy to navigate and code review. No issues observed here.


293-309:

❓ Verification inconclusive

Validate “DELETE” payload usage.

Since deleteApiAuthenticated does not accept a payload, ensure that any usage does not erroneously pass one. If required in the future, you could handle body content or remove it entirely from your type definitions.

Please run a quick check to confirm no code tries to pass a payload to your DELETE method:


🏁 Script executed:

#!/bin/bash
# Searching for any calls to deleteApiAuthenticated that provide a second argument with payload
ast-grep --pattern $'deleteApiAuthenticated($_, { payload: $$$ })'

Length of output: 67


🏁 Script executed:

#!/bin/bash
# Re-run a search for any calls to deleteApiAuthenticated that include "payload"
rg -n "deleteApiAuthenticated\\s*\\([^)]*payload" 

Length of output: 49


DELETE payload usage validated – no payloads found in deleteApiAuthenticated calls
Our searches (using both ast-grep and rg) did not reveal any instances where a payload property is passed to the DELETE method. This confirms that the current implementation is not being misused. Please manually verify across all client usages to ensure no inadvertent payloads are introduced in the future.

  • Verified with an ast-grep search for calls with { payload: ... } and an rg search for any payload-related arguments.

Copy link
Collaborator

@mohitb35 mohitb35 left a comment

Choose a reason for hiding this comment

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

@sunilsabatp LGTM

Do you want to address #2455 (comment)?

@sunilsabatp sunilsabatp merged commit 1fe767a into develop Apr 1, 2025
5 of 6 checks passed
@sunilsabatp sunilsabatp deleted the feature/api branch April 1, 2025 04:57
This was referenced Apr 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants