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

Add support for RESTful APIs as a data source #34

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

cbrianbet
Copy link
Member

@cbrianbet cbrianbet commented Mar 6, 2025

Summary by Sourcery

New Features:

  • Adds support for connecting to RESTful APIs as a data source.

Copy link
Contributor

sourcery-ai bot commented Mar 6, 2025

Reviewer's Guide by Sourcery

This pull request introduces the ability to connect to RESTful APIs, refactors the data upload logic to handle both CSV and API data, updates the logo in the drawer header, and updates the data processing logic for CSV files to handle the data correctly. It also removes the data.pop() call in the validateFile function.

No diagrams generated as the changes look simple and do not need a visual representation.

File-Level Changes

Change Details Files
Implemented functionality to connect to RESTful APIs, including input fields for the endpoint, HTTP method, and JSON data path.
  • Added a new state variable apiFormData to store the API connection details.
  • Added a new state variable apiFormErrors to handle API form validation.
  • Created a new component RestApiDataForm to render the API connection form fields.
  • Added validation logic for the API form fields.
  • Implemented the API connection logic in the handleClick and handleConnectionTest functions.
  • Modified the onNextStep function to pass the API data to the next step.
src/pages/configs/DataAccess/ConnectionDetails.js
src/pages/configs/DataAccess/RestApiDataForm.js
Updated the data processing logic for CSV files to handle the data correctly.
  • Modified the parseCSV function to return the last element of the array.
  • Modified the onNextStep function to pass the CSV data to the next step.
src/helpers/parseCSV.js
src/pages/configs/DataAccess/ConnectionDetails.js
Refactored the data upload logic to handle both CSV and API data.
  • Modified the createConfig function to handle both CSV and API data.
  • Updated the API endpoint for uploading data to /db_access/upload_data.
  • Added a new upload parameter to the data upload request to specify the data type (CSV or API).
src/pages/configs/DataAccess/SaveConfig.js
Updated the logo in the drawer header.
  • Replaced the old logo with a new logo image.
src/layout/MainLayout/Drawer/DrawerHeader/index.js
Removed the data.pop() call in the validateFile function.
  • Removed the data.pop() call in the validateFile function.
src/pages/data-dictionary/UniversalDictionary/ValidateDataDictionaryFile.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai bot changed the title @sourcery-ai Add support for RESTful APIs as a data source Mar 6, 2025
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @cbrianbet - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider extracting the API request logic into a separate reusable function to reduce duplication in handleClick and handleConnectionTest.
  • The body property is commented out in the API request, make sure this is intentional and add a comment explaining why.
Here's what I looked at during the review
  • 🟡 General issues: 2 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

setAlertMessage('Data does not contain JSON key in result')
}
}
setTestLoader(false)
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Streamline testLoader reset using a finally block.

In both API and non-API branches, setTestLoader(false) is explicitly called, and an extra call exists after the conditional block. Using a finally block would guarantee that testLoader is reset without repetitive calls.

Suggested implementation:

                }
            } catch (error) {
                setAlertType('error')
                setAlertMessage(`API connection failed! ${responseData}`)
            } finally {
                setTestLoader(false)

Ensure that any other explicit calls to setTestLoader(false) (if present further down or in other branches of the try block) are removed. Additionally, verify that the API error handling logic (including calls to setAlertMessage) is consistent after this refactoring.

} catch (error) {
setAlertType('error')
console.error('Error testing API connection:', JSON.stringify(error));
setAlertMessage(error)
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider improving error message handling in API fetch.

The current approach sets the alert message directly with the error object. Extracting a more descriptive message (e.g., using error.message) could provide clearer feedback to the user.

Suggested change
setAlertMessage(error)
setAlertMessage(error?.message || 'An unknown error occurred while testing the API connection.')

let conn_str = `${formData.db_type}://${formData.username}:${formData.password}@${formData.host_port}/${formData.database}`
onNextStep({conn_str, conn_type: formData.conn_type});
} else if(handleValidationAPI() && formData.db_type === 'api'){
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider extracting the API connection logic into a reusable utility function to reduce code duplication and deep nesting in handleClick and handleConnectionTest functions, improving maintainability and readability .

Consider extracting the common API connection logic into a small utility so that both handleClick and handleConnectionTest reuse the same logic. This reduces duplication and deep nesting.

For example, you can create a helper function:

const executeAPIRequest = async (apiData, onSuccess, onError) => {
  try {
    const response = await fetch(apiData.endpoint, {
      method: apiData.method,
      headers: { "Content-Type": "application/json" },
      // body: JSON.stringify(apiData.body), // uncomment when needed
    });
    const responseData = await response.json();
    if (!response.ok) {
      throw new Error(`API connection failed! ${JSON.stringify(responseData)}`);
    }
    if (apiData.dataPath && !responseData.hasOwnProperty(apiData.dataPath)) {
      throw new Error("Data does not contain JSON key in result");
    }
    onSuccess(apiData.dataPath ? responseData[apiData.dataPath] : responseData);
  } catch (error) {
    onError(error);
  }
};

Then update your handlers accordingly. For instance, in handleClick:

const handleClick = async () => {
  if (handleValidation() && formData.db_type !== "api") {
    let conn_str = `${formData.db_type}://${formData.username}:${formData.password}@${formData.host_port}/${formData.database}`;
    onNextStep({ conn_str, conn_type: formData.conn_type });
  } else if (handleValidationAPI() && formData.db_type === "api") {
    setTestLoader(true);
    await executeAPIRequest(
      apiFormData,
      (data) => {
        onNextStep({
          conn_str: apiFormData.endpoint,
          conn_type: formData.conn_type,
          db: formData.db_type,
          data,
        });
        setAlertType(null);
        setTestLoader(false);
      },
      (error) => {
        setAlertType("error");
        setAlertMessage(error.message);
        setTestLoader(false);
      }
    );
  }
};

Apply a similar refactoring in handleConnectionTest. This approach removes duplicated fetch logic, reduces deep nesting, and centralizes API error handling without reverting any functionality.

Comment on lines +118 to +133
if (!response.ok) {
setAlertType('error')
setAlertMessage(`API connection failed! ${responseData}`)
} else {
if (responseData.hasOwnProperty(apiFormData.dataPath) || apiFormData.dataPath === '') {
onNextStep({
conn_str: apiFormData.endpoint,
conn_type: formData.conn_type,
db: formData.db_type,
data: responseData[apiFormData.dataPath] ?? responseData
})
} else {
setAlertType('error')
setAlertMessage('Data does not contain JSON key in result')
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Merge else clause's nested if statement into else if (merge-else-if)

Suggested change
if (!response.ok) {
setAlertType('error')
setAlertMessage(`API connection failed! ${responseData}`)
} else {
if (responseData.hasOwnProperty(apiFormData.dataPath) || apiFormData.dataPath === '') {
onNextStep({
conn_str: apiFormData.endpoint,
conn_type: formData.conn_type,
db: formData.db_type,
data: responseData[apiFormData.dataPath] ?? responseData
})
} else {
setAlertType('error')
setAlertMessage('Data does not contain JSON key in result')
}
}
if (!response.ok) {
setAlertType('error')
setAlertMessage(`API connection failed! ${responseData}`)
}
else if (responseData.hasOwnProperty(apiFormData.dataPath) || apiFormData.dataPath === '') {
onNextStep({
conn_str: apiFormData.endpoint,
conn_type: formData.conn_type,
db: formData.db_type,
data: responseData[apiFormData.dataPath] ?? responseData
})
}
else {
setAlertType('error')
setAlertMessage('Data does not contain JSON key in result')
}


ExplanationFlattening if statements nested within else clauses generates code that is
easier to read and expand upon.

Comment on lines +208 to +219
if (!response.ok) {
setAlertType('error')
setAlertMessage(`API connection failed! ${responseData}`)
} else {
if (responseData.hasOwnProperty(apiFormData.dataPath) || apiFormData.dataPath === '') {
setAlertType('success')
setAlertMessage('Successfully connected to API')
} else {
setAlertType('error')
setAlertMessage('Data does not contain JSON key in result')
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Merge else clause's nested if statement into else if (merge-else-if)

Suggested change
if (!response.ok) {
setAlertType('error')
setAlertMessage(`API connection failed! ${responseData}`)
} else {
if (responseData.hasOwnProperty(apiFormData.dataPath) || apiFormData.dataPath === '') {
setAlertType('success')
setAlertMessage('Successfully connected to API')
} else {
setAlertType('error')
setAlertMessage('Data does not contain JSON key in result')
}
}
if (!response.ok) {
setAlertType('error')
setAlertMessage(`API connection failed! ${responseData}`)
}
else if (responseData.hasOwnProperty(apiFormData.dataPath) || apiFormData.dataPath === '') {
setAlertType('success')
setAlertMessage('Successfully connected to API')
}
else {
setAlertType('error')
setAlertMessage('Data does not contain JSON key in result')
}


ExplanationFlattening if statements nested within else clauses generates code that is
easier to read and expand upon.

@cbrianbet cbrianbet requested a review from MaryKilewe March 6, 2025 12:31
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.

1 participant