Skip to content

refactor: address PR review feedback for new-shopify-order-to-slack integration - #79

Open
sdmdg wants to merge 1 commit into
wso2:mainfrom
sdmdg:main
Open

refactor: address PR review feedback for new-shopify-order-to-slack integration#79
sdmdg wants to merge 1 commit into
wso2:mainfrom
sdmdg:main

Conversation

@sdmdg

@sdmdg sdmdg commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Purpose

Addressing code review feedback and refactoring the Shopify-to-Slack integration for better performance, maintainability and traceability.
Resolves PR suggestions from #62.

Goals

  • Improve code quality by utilizing Ballerina's modern features (Query expressions, isolated functions).
  • Enhance log traceability for easier debugging in production.
  • Optimize string manipulation performance by replacing Regex with standard string operations.
  • Improve code maintainability by implementing a map-based placeholder replacement logic.

Approach

  • Logging: Prefixed logs with function names (e.g., onOrdersCreate) for better log filtering.
  • Naming: Renamed escapeHtml to escapeSlackText to better reflect its domain-specific purpose.
  • Performance: Switched from re:replaceAll (Regex) to string:replaceAll to reduce overhead.
  • Refactoring: - Replaced manual foreach loops with Ballerina Query Expressions for list building.
    • Implemented a Map-based replacement system for Slack templates, allowing for easier addition/renaming of tokens.
    • Marked all utility functions as isolated as they do not access mutable module-level state, ensuring thread safety.
  • Redundancy: Removed unnecessary type checks (e.g., is shopify:LineItem[]) where the logic already handled the type or nullability.

Security checks

Related PRs

This PR addresses the feedback provided in the previous PR for the new-shopify-order-to-slack #62.

Test environment

Tested on:

  • Ballerina: 2201.13.1 (Swan Lake)
  • OS: Ubuntu 24.04 (WSL)

Summary by CodeRabbit

  • New Features

    • Enhanced error handling for Slack message construction with proper error propagation
  • Bug Fixes

    • Improved text escaping for Slack message formatting
    • More reliable message deduplication using order numbers
  • Improvements

    • Enhanced logging with clearer prefixes for better troubleshooting

@coderabbitai

coderabbitai Bot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Two Ballerina functions files updated to improve Shopify order-to-Slack integration: functions marked isolated, escapeHtml renamed to escapeSlackText, item list generation refactored to use query syntax, placeholder replacement improved with RegExp, and error handling added to message construction.

Changes

Cohort / File(s) Summary
Isolation & Error Handling
functions.bal
Added import ballerina/lang.regexp. Marked five functions (extractOrderDetails, buildItemsList, buildShippingAddress, escapeSlackText, buildSlackMessage) as isolated. Updated buildSlackMessage return type from string to string|error to propagate errors from message construction.
String Processing Refactoring
functions.bal
Renamed escapeHtml to escapeSlackText and updated all call sites. Reworked buildItemsList to derive items from event?.line_items ?: [] using Ballerina query syntax (from/let/select) instead of if-block with foreach loop. Simplified final string formatting with string:'join() and conditional trailing newline.
Placeholder Replacement Logic
functions.bal
Replaced fixed sequence of re \{...\} replacements with dynamic placeholder iteration: populates map<string> with escaped values, performs <br> replacement via compiled RegExp, and iterates placeholders.entries() using regexp:fromString("\\{" + placeholder + "\\}") for each replacement.
Control Flow & Error Propagation
main.bal
Simplified clientMsgId assignment logic from conditional branch to single ternary expression (orderNumber when hasRealOrderId, else uuid:createType1AsString()). Added check keyword to buildSlackMessage call to propagate errors. Updated logging to prefix messages with function name context.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hoppy times with isolated hops,
RegExp magic makes logic stops,
Error-checked messages bounce so bright,
Query syntax keeps functions tight,
From Shopify's orders to Slack's delight!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: refactoring to address PR review feedback for the Shopify-to-Slack integration, which aligns with the changeset's focus on code quality improvements and modernization.
Description check ✅ Passed The description covers Purpose, Goals, Approach, Security checks, Related PRs, and Test environment sections. It provides clear context for the refactoring work and addresses most template requirements, though some sections (Marketing, Automation tests, Samples, Learning, Migrations) are not applicable to this change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ballerina-integrator/new-shopify-order-to-slack/functions.bal`:
- Line 96: The buildSlackMessage function currently only replaces known tokens
(e.g., order id, totalPrice) and leaves unknown {…} tokens (from the
configurable template/customMessage) unvalidated; update buildSlackMessage to
perform a post-replacement scan of the resulting string for any remaining
`{...}` tokens and return an error if any are found (include the offending
token(s) in the error message) instead of returning the broken string—this
ensures typos like `{totlPrice}` fail fast; locate the token-replacement logic
in buildSlackMessage and add the validation step immediately after replacements,
returning string|error accordingly.
- Around line 61-67: The returned items block currently appends a trailing
newline to the joined itemLines expression; remove the "+ (itemLines.length() >
0 ? "\n" : "")" suffix in the return so itemsDetails is just string:'join("\n",
...itemLines) (this prevents the extra blank line before Subtotal while
preserving the joined lines built from itemLines and quantities/product names).

In `@ballerina-integrator/new-shopify-order-to-slack/main.bal`:
- Around line 24-25: The current clientMsgId uses uuid:createType1AsString()
when orderDetails.hasRealOrderId is false, which produces a new value on
retries; instead compute a stable fallback by hashing stable order fields (e.g.,
orderDetails.orderNumber, orderDetails.createdAt, orderDetails.customerEmail or
orderDetails.shopifyId) so the same event yields the same client_msg_id on
retry. Replace the uuid call in the clientMsgId assignment with a deterministic
hash of those stable fields (use the existing crypto/hash utility in the project
or add one) so clientMsgId remains stable across retries while preserving the
branch that uses orderDetails.orderNumber when hasRealOrderId is true.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 683d668d-262a-4e1d-89d4-33cd6d2f5f87

📥 Commits

Reviewing files that changed from the base of the PR and between 15322bb and 8838f92.

📒 Files selected for processing (2)
  • ballerina-integrator/new-shopify-order-to-slack/functions.bal
  • ballerina-integrator/new-shopify-order-to-slack/main.bal

Comment on lines +61 to +67
string[] itemLines = from shopify:LineItem item in lineItems
let int? quantity = item?.quantity
let string quantityStr = quantity is int ? quantity.toString() : "1"
let string productName = item?.name ?: "Unknown Product"
select " • " + quantityStr + "x " + productName;

return itemsDetails;
return string:'join("\n", ...itemLines) + (itemLines.length() > 0 ? "\n" : "");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Drop the extra newline from itemsDetails.

Line 67 appends "\n", and the default template in ballerina-integrator/new-shopify-order-to-slack/config.bal:8-9 already adds a <br> immediately after {items}. That leaves a blank line before Subtotal for every non-empty order.

♻️ Suggested fix
-    return string:'join("\n", ...itemLines) + (itemLines.length() > 0 ? "\n" : "");
+    return string:'join("\n", ...itemLines);
📝 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
string[] itemLines = from shopify:LineItem item in lineItems
let int? quantity = item?.quantity
let string quantityStr = quantity is int ? quantity.toString() : "1"
let string productName = item?.name ?: "Unknown Product"
select "" + quantityStr + "x " + productName;
return itemsDetails;
return string:'join("\n", ...itemLines) + (itemLines.length() > 0 ? "\n" : "");
string[] itemLines = from shopify:LineItem item in lineItems
let int? quantity = item?.quantity
let string quantityStr = quantity is int ? quantity.toString() : "1"
let string productName = item?.name ?: "Unknown Product"
select "" + quantityStr + "x " + productName;
return string:'join("\n", ...itemLines);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-integrator/new-shopify-order-to-slack/functions.bal` around lines
61 - 67, The returned items block currently appends a trailing newline to the
joined itemLines expression; remove the "+ (itemLines.length() > 0 ? "\n" : "")"
suffix in the return so itemsDetails is just string:'join("\n", ...itemLines)
(this prevents the extra blank line before Subtotal while preserving the joined
lines built from itemLines and quantities/product names).


// Builds the Slack message by replacing placeholders with actual values
function buildSlackMessage(OrderDetails details, string template) returns string {
isolated function buildSlackMessage(OrderDetails details, string template) returns string|error {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fail fast on unknown template tokens.

Lines 121-124 only replace known keys. Because customMessage is configurable, a typo like {totlPrice} will survive unchanged and get posted as broken notification text. Since this helper already returns string|error, validate after the replacement pass that no {...} tokens remain and surface that as an error or warning.

Also applies to: 121-124

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-integrator/new-shopify-order-to-slack/functions.bal` at line 96,
The buildSlackMessage function currently only replaces known tokens (e.g., order
id, totalPrice) and leaves unknown {…} tokens (from the configurable
template/customMessage) unvalidated; update buildSlackMessage to perform a
post-replacement scan of the resulting string for any remaining `{...}` tokens
and return an error if any are found (include the offending token(s) in the
error message) instead of returning the broken string—this ensures typos like
`{totlPrice}` fail fast; locate the token-replacement logic in buildSlackMessage
and add the validation step immediately after replacements, returning
string|error accordingly.

Comment on lines +24 to +25
// Determine client_msg_id for deduplication
string clientMsgId = orderDetails.hasRealOrderId ? orderDetails.orderNumber : uuid:createType1AsString();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use a stable fallback for the dedupe key.

Line 25 generates a fresh value whenever hasRealOrderId is false. If the same event is retried in that state, it will get a different client_msg_id each time and can be posted more than once. Derive the fallback from stable order fields instead of minting a new value here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-integrator/new-shopify-order-to-slack/main.bal` around lines 24 -
25, The current clientMsgId uses uuid:createType1AsString() when
orderDetails.hasRealOrderId is false, which produces a new value on retries;
instead compute a stable fallback by hashing stable order fields (e.g.,
orderDetails.orderNumber, orderDetails.createdAt, orderDetails.customerEmail or
orderDetails.shopifyId) so the same event yields the same client_msg_id on
retry. Replace the uuid call in the clientMsgId assignment with a deterministic
hash of those stable fields (use the existing crypto/hash utility in the project
or add one) so clientMsgId remains stable across retries while preserving the
branch that uses orderDetails.orderNumber when hasRealOrderId is true.

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