Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Website: API Service changed #2231

Merged
merged 5 commits into from
Nov 14, 2024
Merged

Website: API Service changed #2231

merged 5 commits into from
Nov 14, 2024

Conversation

OchiengPaul442
Copy link
Contributor

@OchiengPaul442 OchiengPaul442 commented Nov 14, 2024

Summary of Changes (What does this PR do?)

  • Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Status of maturity (all need to be checked before merging):

  • I've tested this locally
  • I consider this code done
  • This change ready to hit production in its current state
  • The title of the PR states what changed and the related issues number (used for the release note).
  • I've included issue number in the "Closes #ISSUE-NUMBER" part of the "What are the relevant tickets?" section to link the issue.
  • I've updated corresponding documentation for the changes in this PR.
  • I have written unit and/or e2e tests for my change(s).

How should this be manually tested?

  • Please include the steps to be done inorder to setup and test this PR.

What are the relevant tickets?

Screenshots (optional)

Summary by CodeRabbit

  • New Features

    • Introduced a new API endpoint for retrieving grid summaries.
    • Consolidated API URL configurations for improved clarity.
  • Bug Fixes

    • Enhanced error messages for better context during API calls.
  • Chores

    • Updated the environment variable configurations to streamline API interactions.

Copy link

coderabbitai bot commented Nov 14, 2024

📝 Walkthrough

Walkthrough

The changes in this pull request involve modifications to environment variable configurations and API URL handling across several files. The variable NEXT_PUBLIC_DJANGO_API_URL has been removed and replaced with NEXT_PUBLIC_API_URL, consolidating API URL management. Additionally, a new function getGridsSummary has been introduced to conditionally fetch data based on the environment. The API base URL construction has been updated to ensure proper formatting, while existing functionalities and error handling remain intact.

Changes

File Path Change Summary
website2/.env.sample - Removed: NEXT_PUBLIC_DJANGO_API_URL
- Removed: NEXT_PUBLIC_EXTERNAL_API_URL
- Added: NEXT_PUBLIC_API_URL=https://external-api-url
website2/src/app/api/proxy/route.ts - Updated: const API_BASE_URL to use NEXT_PUBLIC_API_URL instead of NEXT_PUBLIC_EXTERNAL_API_URL
website2/src/components/sections/footer/CountrySelectorDialog.tsx - Added import for getGridsSummary
- Modified fetchAirqloudSummary to conditionally fetch data based on environment
website2/src/services/apiService/index.tsx - Updated API base URL configuration to use NEXT_PUBLIC_API_URL with removeTrailingSlash utility
website2/src/services/externalService/index.tsx - Added constant API_TOKEN from NEXT_PUBLIC_API_TOKEN
- Added method getGridsSummary for new API call
- Updated API_BASE_URL to use NEXT_PUBLIC_API_URL

Possibly related PRs

Suggested reviewers

  • Baalmart

Poem

In the code where APIs play,
URLs change, come what may.
From Django's grasp to a new embrace,
A single path now takes its place.
Grids are fetched with a clever twist,
In the world of code, none can resist! 🌐✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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 resolve resolve all the CodeRabbit review comments.
  • @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 or @coderabbitai title 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

@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: 6

🧹 Outside diff range and nitpick comments (3)
website2/src/app/api/proxy/route.ts (1)

Line range hint 63-73: Remove or configure production logging

The extensive console logging in the POST route might expose sensitive information in production. Consider:

  1. Using a proper logging service
  2. Implementing environment-based logging levels
-    // Log to check what the remaining body looks like
-    console.log('Received body (without endpoint):', body);
-    // Log the URL you're about to make the request to
-    console.log('API URL:', apiUrl);
website2/src/services/apiService/index.tsx (1)

1-1: Consider architectural improvements for better type safety and error handling

While the current changes look good, here are some suggestions for future improvements:

  1. Add TypeScript interfaces for API responses
  2. Implement request timeout in axios configuration
  3. Add request interceptors for consistent error handling
  4. Consider implementing retry logic for failed requests

Example implementation:

// Response interfaces
interface ApiResponse<T> {
  data: T;
  status: number;
}

// Axios configuration
const apiClient = axios.create({
  baseURL: API_BASE_URL,
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Error interceptor
apiClient.interceptors.response.use(
  response => response,
  error => {
    if (error.response?.status === 404) {
      console.warn('Resource not found:', error.config.url);
    }
    return Promise.reject(error);
  }
);
website2/src/components/sections/footer/CountrySelectorDialog.tsx (1)

83-104: Consider environment configuration improvements

The current environment-based conditional logic could be better handled through a service layer abstraction.

Consider creating an API service layer that handles environment differences:

// services/api/gridsService.ts
export class GridsService {
  private static async fetchGrids(): Promise<GridsSummaryResponse> {
    if (process.env.NODE_ENV === 'development') {
      return fetch('/api/proxy?endpoint=devices/grids/summary')
        .then(response => {
          if (!response.ok) throw new Error(response.statusText);
          return response.json();
        });
    }
    return getGridsSummary();
  }

  public static async getGridsSummary(): Promise<GridsSummaryResponse> {
    try {
      const data = await this.fetchGrids();
      if (!data?.grids) {
        throw new Error('Invalid response structure');
      }
      return data;
    } catch (error) {
      throw new Error(`Failed to fetch grids: ${error.message}`);
    }
  }
}

This approach would:

  1. Encapsulate environment-specific logic
  2. Provide a consistent interface for components
  3. Make testing and maintenance easier
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 65e1add and 13931be.

📒 Files selected for processing (5)
  • website2/.env.sample (1 hunks)
  • website2/src/app/api/proxy/route.ts (1 hunks)
  • website2/src/components/sections/footer/CountrySelectorDialog.tsx (2 hunks)
  • website2/src/services/apiService/index.tsx (1 hunks)
  • website2/src/services/externalService/index.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • website2/.env.sample
🔇 Additional comments (5)
website2/src/services/externalService/index.tsx (1)

52-52: Verify API endpoint configuration

Let's ensure the endpoint path is consistent with other usages in the codebase.

✅ Verification successful

API endpoint /devices/grids/summary is consistently used across the codebase

The endpoint is correctly used and appears in multiple services:

  • reports/src/services/api/index.tsx
  • platform/src/core/urls/deviceRegistry.js
  • website/frontend/config/urls.js
  • website2/src/services/externalService/index.tsx

The implementation aligns with existing usage patterns in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other instances of this endpoint
rg -g '!*.{json,md}' '/devices/grids/summary'

# Check for any similar grid-related endpoints
rg -g '!*.{json,md}' '/devices/grids/'

Length of output: 1006

website2/src/app/api/proxy/route.ts (3)

Line range hint 8-45: LGTM: GET route implementation

The GET route implementation looks good with proper:

  • URL construction
  • Error handling
  • Response handling

Line range hint 47-95: LGTM: POST route implementation

The POST route implementation looks good with proper:

  • Request body handling
  • Error handling
  • Response handling

5-6: Verify environment variable updates across the application

The change from NEXT_PUBLIC_EXTERNAL_API_URL to NEXT_PUBLIC_API_URL needs to be consistently applied across all environments and documentation.

website2/src/components/sections/footer/CountrySelectorDialog.tsx (1)

19-19: Verify external service dependency implementation

Let's ensure the imported getGridsSummary function is properly implemented in the external service.

✅ Verification successful

External service dependency is properly implemented

The getGridsSummary function is correctly implemented in website2/src/services/externalService/index.tsx. It's an authenticated API endpoint that:

  • Makes a GET request to '/devices/grids/summary'
  • Uses the API token for authentication
  • Handles errors appropriately
  • Returns the response data or null on error
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of getGridsSummary in the external service

# Search for the function definition
ast-grep --pattern 'export const getGridsSummary = $_' || ast-grep --pattern 'export function getGridsSummary($_)'

# Search for any usage of this function
rg "getGridsSummary" --type ts --type tsx

Length of output: 1178


Script:

#!/bin/bash
# Search for getGridsSummary usage with proper file type options
rg "getGridsSummary" -t typescript -t tsx

# Verify the external service file structure and exports
rg "export" -t typescript -t tsx website2/src/services/externalService/

Length of output: 183


Script:

#!/bin/bash
# Search for getGridsSummary usage without file type restrictions
rg "getGridsSummary"

# Check the content of the external service file
cat website2/src/services/externalService/index.tsx

Length of output: 2630

Comment on lines +5 to +6
const API_BASE_URL = removeTrailingSlash(process.env.NEXT_PUBLIC_API_URL || '');
const API_TOKEN = process.env.NEXT_PUBLIC_API_TOKEN || '';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Review security implications of exposing API token

The NEXT_PUBLIC_ prefix makes this token available in the client-side bundle. Consider if this level of exposure is necessary, as client-side tokens can be extracted and potentially misused.

Consider these alternatives:

  1. Move token-dependent requests to API routes
  2. Implement request signing
  3. Add rate limiting and domain restrictions

Comment on lines +49 to +63
// Get grids summary endpoint it uses a api_token to authenticate the request
export const getGridsSummary = async (): Promise<any | null> => {
try {
const response = await apiClient.get('/devices/grids/summary', {
params: {
token: API_TOKEN,
},
});

return response.data;
} catch (error) {
console.error('Error fetching grids summary data:', error);
return null;
}
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance type safety and error handling

The implementation could benefit from several improvements:

  1. The return type Promise<any | null> is too permissive
  2. Returning null on error might hide important error information
  3. Comment style differs from other functions (uses inline comment vs JSDoc)

Consider this improved implementation:

-// Get grids summary endpoint it uses a api_token to authenticate the request
+/**
+ * Fetches summary data for all grids
+ * @returns {Promise<GridSummary | Error>} The grids summary data or error
+ */
-export const getGridsSummary = async (): Promise<any | null> => {
+interface GridSummary {
+  // define your expected response structure here
+}
+
+export const getGridsSummary = async (): Promise<GridSummary> => {
   try {
     const response = await apiClient.get('/devices/grids/summary', {
       params: {
         token: API_TOKEN,
       },
     });
 
-    return response.data;
+    return response.data as GridSummary;
   } catch (error) {
     console.error('Error fetching grids summary data:', error);
-    return null;
+    throw error;
   }
 };

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +5 to 6
const API_BASE_URL = removeTrailingSlash(process.env.NEXT_PUBLIC_API_URL || '');
const API_TOKEN = process.env.NEXT_PUBLIC_API_TOKEN || '';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider security implications of public environment variables

Using NEXT_PUBLIC_API_TOKEN exposes the token in the client-side bundle. Consider:

  1. Moving token handling to a secure backend endpoint
  2. Implementing proper authentication mechanisms
  3. Using runtime environment variables instead of build-time ones

process.env.NEXT_PUBLIC_DJANGO_API_URL || 'http://127.0.0.1:8000/api';
import { removeTrailingSlash } from '@/utils';

const API_BASE_URL = `${removeTrailingSlash(process.env.NEXT_PUBLIC_API_URL || '')}/website`;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding URL validation and proper fallback

The current implementation might result in invalid URLs if NEXT_PUBLIC_API_URL is not set. Consider adding validation and a proper fallback URL.

Here's a suggested improvement:

-const API_BASE_URL = `${removeTrailingSlash(process.env.NEXT_PUBLIC_API_URL || '')}/website`;
+const DEFAULT_API_URL = 'http://localhost:8000';
+const apiUrl = process.env.NEXT_PUBLIC_API_URL || DEFAULT_API_URL;
+const API_BASE_URL = `${removeTrailingSlash(apiUrl)}/website`;
+
+if (!API_BASE_URL.startsWith('http')) {
+  console.warn('Invalid API URL configuration detected');
+}
📝 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
const API_BASE_URL = `${removeTrailingSlash(process.env.NEXT_PUBLIC_API_URL || '')}/website`;
const DEFAULT_API_URL = 'http://localhost:8000';
const apiUrl = process.env.NEXT_PUBLIC_API_URL || DEFAULT_API_URL;
const API_BASE_URL = `${removeTrailingSlash(apiUrl)}/website`;
if (!API_BASE_URL.startsWith('http')) {
console.warn('Invalid API URL configuration detected');
}

Comment on lines +3 to +5
import { removeTrailingSlash } from '@/utils';

const API_BASE_URL = `${removeTrailingSlash(process.env.NEXT_PUBLIC_API_URL || '')}/website`;
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Environment variable transition needs configuration updates

The switch from NEXT_PUBLIC_DJANGO_API_URL to NEXT_PUBLIC_API_URL requires the following actions:

  • Update the Dockerfile in website2/ to use NEXT_PUBLIC_API_URL instead of NEXT_PUBLIC_DJANGO_API_URL
  • The new variable NEXT_PUBLIC_API_URL is consistently used across multiple services (apiService, externalService, proxy route)
  • All URL constructions properly handle empty values with fallbacks

The verification revealed that while the codebase has mostly transitioned to the new environment variable, the Dockerfile still references the old one, which could cause deployment issues. The URL construction itself is safe with proper empty string fallbacks and trailing slash handling.

🔗 Analysis chain

Verify environment variable configuration across all environments

The switch from NEXT_PUBLIC_DJANGO_API_URL to NEXT_PUBLIC_API_URL requires verification of environment configurations.

Let's check the environment variable usage:


Let's get a more comprehensive view of the environment variable usage and configuration across the codebase, including hidden files and deployment configurations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify environment variable usage and configuration files

# Check for any remaining references to old env var
echo "Checking for old environment variable references..."
rg "NEXT_PUBLIC_DJANGO_API_URL"

# Look for .env files and environment configuration
echo "Checking environment configuration files..."
fd -t f "^\.env" -X cat

Length of output: 609


Script:

#!/bin/bash
# Description: Comprehensive check for environment variable usage and configuration

# Check for both old and new environment variable references
echo "Checking environment variable references..."
rg -A 2 "NEXT_PUBLIC_.*API_URL"

# Check Dockerfile and deployment configs with hidden files
echo "Checking configuration files..."
fd -H -t f "(Dockerfile|\.env.*|docker-compose.*\.yml|\.env$)" -X cat

# Check for any potential URL construction in the codebase
echo "Checking URL construction patterns..."
rg "process\.env\.NEXT_PUBLIC.*URL.*" -A 2

Length of output: 13072

Comment on lines +81 to +104
let data;

if (process.env.NODE_ENV === 'development') {
// Use proxy in development
const response = await fetch(
`/api/proxy?endpoint=devices/grids/summary`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
signal: abortSignal,
},
signal: abortSignal,
},
);
);

if (!response.ok) {
throw new Error(`Error: ${response.statusText}`);
}
if (!response.ok) {
throw new Error(`Error: ${response.statusText}`);
}

const data = await response.json();
data = await response.json();
} else {
// Use getGridsSummary in production
data = await getGridsSummary();
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add type safety and improve error handling

The environment-based conditional logic is well-structured, but there are a few improvements we can make:

  1. Add type safety for the API response
  2. Handle errors explicitly for getGridsSummary
  3. Ensure consistent response structure between environments

Consider applying these changes:

 let data;

 if (process.env.NODE_ENV === 'development') {
   // Use proxy in development
   const response = await fetch(
     `/api/proxy?endpoint=devices/grids/summary`,
     {
       method: 'GET',
       headers: {
         'Content-Type': 'application/json',
       },
       signal: abortSignal,
     },
   );

   if (!response.ok) {
     throw new Error(`Error: ${response.statusText}`);
   }

   data = await response.json();
 } else {
   // Use getGridsSummary in production
-  data = await getGridsSummary();
+  try {
+    data = await getGridsSummary();
+    if (!data?.grids) {
+      throw new Error('Invalid response structure from getGridsSummary');
+    }
+  } catch (error) {
+    throw new Error(`Error fetching grids summary: ${error.message}`);
+  }
 }

Also, consider adding a type interface for the API response:

interface GridsSummaryResponse {
  grids: Array<{
    _id: string;
    name: string;
    long_name: string;
    admin_level: string;
    numberOfSites: number;
  }>;
}

Copy link
Collaborator

@Baalmart Baalmart left a comment

Choose a reason for hiding this comment

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

@Baalmart Baalmart merged commit e034347 into staging Nov 14, 2024
29 checks passed
@Baalmart Baalmart deleted the website2-deployment branch November 14, 2024 12:34
@Baalmart Baalmart mentioned this pull request Nov 14, 2024
2 tasks
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