Improve sample Twilio connector code - #137
Conversation
📝 WalkthroughChanges SummaryThis pull request enhances the Twilio connector sample code by expanding the automation workflow and improving the trigger sample implementation. Configuration EnhancementsThe Twilio connector configuration now includes additional parameters for controlling call behavior: New TwiML HTTP ServiceA new file introduces a dedicated TwiML HTTP service that responds to voice requests with dynamic XML responses. The service is configured to run on a separate port (8091) and incorporates the configurable message text into the TwiML response payload. This service supports the callback mechanism for Twilio voice interactions. Improved Automation SampleThe automation sample workflow now initiates a Twilio call before sending a message, using the newly configurable parameters. Both operations extract and log their respective identifiers (call SID and message SID), providing better visibility into the connector's activity. The previous hardcoded inline message creation was replaced with parameterized calls. Enhanced Trigger SampleThe trigger sample has been refactored to simplify SMS status handling and add comprehensive call status logging. Key improvements include:
These changes provide a more complete example of Twilio integration capabilities, including both outbound messaging/calling and inbound webhook handling. WalkthroughThe pull request enhances two Twilio integration samples. The connector sample extends its automation to initiate voice calls before sending messages, introducing configurable parameters for call routing and callbacks. A new TwiML HTTP endpoint serves dynamic call scripts. The trigger sample refactors error handling for consistency, standardizes return type signatures across status callbacks, and adds comprehensive call status lifecycle tracking alongside existing SMS status handling. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@integrator-default-profile/connectors/twilio_connector_sample/main.bal`:
- Around line 12-20: Update the Content-Type header in the TwiML responder:
inside the service /twiml's resource function post voice() where twimlResponse
is created and setHeader("Content-Type", "application/xml") is called, change
the header value to "text/xml"; optionally, when building the payload string for
twimlResponse.setPayload(...), add language and voice attributes to the <Say>
verb (e.g., language="en-US" voice="man") if desired.
In `@integrator-default-profile/connectors/twilio_trigger_sample/main.bal`:
- Around line 7-42: The extra Twilio status callbacks onBusy, onFailed,
onNoAnswer, and onCanceled are unused for voice StatusCallbackEvent and should
be removed or clearly documented if they target a different Twilio service;
update the service by deleting these remote functions (onBusy, onFailed,
onNoAnswer, onCanceled) if you only handle voice events, or add a comment
explaining their intended purpose and the alternative Twilio event types if
they’re required for messaging/other webhooks, keeping only onQueued, onRinging,
onInProgress, and onCompleted for voice.
🪄 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: a3bca0ea-8d4e-4892-89fc-e3af5e153b5f
📒 Files selected for processing (4)
integrator-default-profile/connectors/twilio_connector_sample/automation.balintegrator-default-profile/connectors/twilio_connector_sample/config.balintegrator-default-profile/connectors/twilio_connector_sample/main.balintegrator-default-profile/connectors/twilio_trigger_sample/main.bal
| service /twiml on new http:Listener(twimlPort) { | ||
| resource function post voice() returns http:Response { | ||
| http:Response twimlResponse = new; | ||
| twimlResponse.setHeader("Content-Type", "application/xml"); | ||
| twimlResponse.setPayload(string `<?xml version="1.0" encoding="UTF-8"?><Response><Say>${callMessage}</Say></Response>`); | ||
| log:printInfo(`TwiML ${callMessage} response sent`); | ||
| return twimlResponse; | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
What is the correct TwiML XML format and Content-Type header for Twilio voice call responses with the Say verb?
💡 Result:
Correct TwiML XML format (for a Voice response that uses the verb): Hello! This must be valid TwiML: the root element is and all verbs (like ) must be nested inside it.[1] Correct Content-Type header for the HTTP response containing that TwiML: Content-Type: text/xml Twilio’s docs state that when your application responds with XML, Twilio interprets it as TwiML when the response Content-Type is one of text/xml, application/xml, or text/html; text/xml is the most commonly used value.[1] For status-callback endpoints specifically, Twilio says to respond with 200 OK and Content-Type: text/xml (with an empty body, or use 204 No Content).[1] Note: If you’re returning TwiML from your webhook (not just a status callback), you still generally want XML content types; per Twilio, text/xml/application/xml/text/html are treated as the TwiML XML Instruction Set.[1]
Citations:
Use text/xml for the Content-Type header instead of application/xml.
Twilio's documentation indicates that while application/xml is accepted, text/xml is the most commonly used and recommended Content-Type for TwiML responses. The XML structure and <Say> verb formatting are correct; however, the header should be changed from "application/xml" to "text/xml" to align with Twilio best practices.
Optionally, consider adding language and voice attributes to the <Say> verb (e.g., language="en-US" and voice="man"), though these are not required.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@integrator-default-profile/connectors/twilio_connector_sample/main.bal`
around lines 12 - 20, Update the Content-Type header in the TwiML responder:
inside the service /twiml's resource function post voice() where twimlResponse
is created and setHeader("Content-Type", "application/xml") is called, change
the header value to "text/xml"; optionally, when building the payload string for
twimlResponse.setPayload(...), add language and voice attributes to the <Say>
verb (e.g., language="en-US" voice="man") if desired.
| service twilio:CallStatusService on twilioListener { | ||
|
|
||
| remote function onQueued(twilio:CallStatusEventWrapper event) returns error? { | ||
| log:printInfo("Call queued", callSid = event.CallSid ?: ""); | ||
| } | ||
|
|
||
| remote function onRinging(twilio:CallStatusEventWrapper event) returns error? { | ||
| log:printInfo("Call ringing", callSid = event.CallSid ?: ""); | ||
| } | ||
|
|
||
| remote function onInProgress(twilio:CallStatusEventWrapper event) returns error? { | ||
| log:printInfo("Call in progress", callSid = event.CallSid ?: ""); | ||
| } | ||
|
|
||
| remote function onCompleted(twilio:CallStatusEventWrapper event) returns error? { | ||
| log:printInfo("Call completed", | ||
| callSid = event.CallSid ?: "", | ||
| duration = event.CallDuration ?: ""); | ||
| } | ||
|
|
||
| remote function onBusy(twilio:CallStatusEventWrapper event) returns error? { | ||
| log:printInfo("Call busy", callSid = event.CallSid ?: ""); | ||
| } | ||
|
|
||
| remote function onFailed(twilio:CallStatusEventWrapper event) returns error? { | ||
| log:printInfo("Call failed", callSid = event.CallSid ?: ""); | ||
| } | ||
|
|
||
| remote function onNoAnswer(twilio:CallStatusEventWrapper event) returns error? { | ||
| log:printInfo("Call no answer", callSid = event.CallSid ?: ""); | ||
| } | ||
|
|
||
| remote function onCanceled(twilio:CallStatusEventWrapper event) returns error? { | ||
| log:printInfo("Call canceled", callSid = event.CallSid ?: ""); | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check Twilio trigger connector documentation for event name mappings
rg -n "StatusCallbackEvent|onQueued|onInProgress|initiated|answered" --type=bal -C 3Repository: wso2/integration-samples
Length of output: 96
🌐 Web query:
What are the valid StatusCallbackEvent values for Twilio voice calls and how do they map to Ballerina Twilio trigger service callback methods?
💡 Result:
Valid Twilio Voice StatusCallbackEvent values (Programmable Voice / REST or TwiML) are: initiated, ringing, answered, completed. Twilio’s voice webhooks docs explicitly list these events as the supported StatusCallbackEvent values when subscribing to additional status events beyond the default completed callback.[1] How they map to Ballerina Twilio trigger service callback methods (ballerinax/trigger.twilio Call status events): - initiated -> remote function onQueued(...) [2] - ringing -> remote function onRinging(...) [2] - answered -> remote function onInProgress(...) [2] - completed -> remote function onCompleted(...) [2] Note: The Ballerina trigger uses CallStatusEventWrapper callback method names (onQueued/onRinging/onInProgress/onCompleted) rather than the exact Twilio StatusCallbackEvent strings; the mapping above reflects which wrapper callback names the trigger exposes for those same call lifecycle phases.[2][1]
Citations:
- 1: https://www.twilio.com/docs/usage/webhooks/voice-webhooks
- 2: https://central.ballerina.io/ballerinax/trigger.twilio/latest
Remove unused Twilio status callbacks or clarify their purpose.
The service defines callbacks for onBusy, onFailed, onNoAnswer, and onCanceled, but Twilio voice webhooks only support four StatusCallbackEvent values: initiated, ringing, answered, and completed. These four additional callbacks will never be invoked. Either remove them or document if they are intended for a different Twilio service type (e.g., messaging). The currently configured callbacks (onQueued, onRinging, onInProgress, onCompleted) correctly map to their respective Twilio events.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@integrator-default-profile/connectors/twilio_trigger_sample/main.bal` around
lines 7 - 42, The extra Twilio status callbacks onBusy, onFailed, onNoAnswer,
and onCanceled are unused for voice StatusCallbackEvent and should be removed or
clearly documented if they target a different Twilio service; update the service
by deleting these remote functions (onBusy, onFailed, onNoAnswer, onCanceled) if
you only handle voice events, or add a comment explaining their intended purpose
and the alternative Twilio event types if they’re required for messaging/other
webhooks, keeping only onQueued, onRinging, onInProgress, and onCompleted for
voice.
Purpose
Goals
Approach
User stories
Release note
Documentation
Training
Certification
Marketing
Automation tests
Security checks
Samples
Related PRs
Migrations (if applicable)
Test environment
Learning