Skip to content

Instantly share code, notes, and snippets.

@tsnow
Last active December 27, 2015 22:39
Show Gist options
  • Save tsnow/7400112 to your computer and use it in GitHub Desktop.
Save tsnow/7400112 to your computer and use it in GitHub Desktop.
Twilio "Dial Someone Else" Flow
// When your user wants to call someone, they call your /make_call webservice:
// yourserver.com POST /{user_id}/make_call.json?To={OtherParticipantPhoneNumber}
//
// You then ask Twilio to call your user (user_id)'s phone number.
// You'll then tell Twilio to call the other participant's phone number.
//
// yourserver.com Client => api.twilio.com POST /2010-04-01/Accounts/{AccountSid}/Calls{?From,To,Url}
// From: a twilio phone number
// To: first participant (user_id)'s phone number
// Url: the url for 2_call_logic.xml below. Probably something like:
// http://yourserver.com/{user_id}/calls/{OtherParticipantsPhoneNumber}/callback.xml
//
// https://www.twilio.com/docs/api/rest/making-calls
//
// Twilio's Response:
{
"sid": "CAa346467ca321c71dbd5e12f627deb854",
"date_created": "Thu, 19 Aug 2010 00:12:15 +0000",
"date_updated": "Thu, 19 Aug 2010 00:12:15 +0000",
"parent_call_sid": null,
"account_sid": "AC228ba7a5fe4238be081ea6f3c44186f3",
"to": "+14155551212",
"formatted_to": "(415) 555-1212",
"from": "+14158675309",
"formatted_from": "(415) 867-5309",
"phone_number_sid": "PNd6b0e1e84f7b117332aed2fd2e5bbcab",
"status": "queued",
"start_time": null,
"end_time": null,
"duration": null,
"price": null,
"direction": "outbound-api",
"answered_by": null,
"api_version": "2010-04-01",
"forwarded_from": null,
"caller_name": null,
"uri": "\/2010-04-01\/Accounts\/AC228ba7a5fe4238be081ea6f3c44186f3\/Calls\/CAa346467ca321c71dbd5e12f627deb854.json",
"subresource_uris": {
"notifications": "\/2010-04-01\/Accounts\/AC228ba7a5fe4238be081ea6f3c44186f3\/Calls\/CAa346467ca321c71dbd5e12f627deb854\/Notifications.json",
"recordings": "\/2010-04-01\/Accounts\/AC228ba7a5fe4238be081ea6f3c44186f3\/Calls\/CAa346467ca321c71dbd5e12f627deb854\/Recordings.json"
}
}
// Your /make_call webservice's response
{
"result": {
"status": "success"
}
}
<!--
Twilio needs to know what to do with the call, so it asks your app for an xml program
at the url you've provided to it:
(http://yourserver.com/{user_id}/calls/{OtherParticipantsPhoneNumber}/callback.xml)
yourserver.com POST {Url} <= Twilio Server
... lots of parameters
https://www.twilio.com/docs/api/twiml/twilio_request#synchronous
https://www.twilio.com/docs/api/twiml/dial#attributes-action-parameters
Response:
-->
<?xml version="1.0" ?>
<Response>
<Say>Please wait while we connect you to your driver</Say>
<Dial timeout="15" action="{CallCompletedUrl}">
{OtherParticipantPhoneNumber}
</Dial>
</Response>
<!-- CallCompletedUrl would be something like:
http://yourserver.com/{user_id}/calls/{OtherParticipantsPhoneNumber}/call_completed.xml
-->
<!--
When one of the participants hangs up,
twilio will again request from your application additional logic
to determine how to proceed now that the Dial action has completed.
(http://yourserver.com/{user_id}/calls/{OtherParticipantsPhoneNumber}/call_completed.xml)
yourserver.com POST {CallCompletedUrl} <= Twilio Server
DialCallStatus=completed
DialCallSid=whatever%20sid
DialCallDuration=1000
https://www.twilio.com/docs/api/twiml/dial#attributes-action-parameters
Response:
-->
<?xml version="1.0" ?>
<Response>
<Say>This call has ended. Goodbye</Say>
</Response>

Coupling Concerns

  • TwiML: Both sides must understand TwiML documents: the client to generate the appropriate and valid callback XML, and twilio's callback client to be able to parse and interpret them.
  • Call flow state machine: yourserver.com must understand all possible state transitions for the Dial action and the Calls creation action.
  • Calls creation request form:
    1. yourserver.com must understand the Calls creation response data structure, including the names and values of all relevant components.
    2. yourserver.com must know the Calls creation URL
    3. yourserver.com must understand the names and values of the Calls creation URL parameters
  • callback request forms:
    1. yourserver.com must understand the names and values of the Calls callback request parameters
    2. yourserver.com must understand the names and values of the Dial callback request parameters
  • both sides must agree regarding the name and value of the AccountSid
  • both sides must agree on the method, occurrances, and content of authentication.

Decoupled Components

  • Twilio need not understand any yourserver.com logic or state, save for:
    1. the Calls Url parameter will contain an endpoint which understands the Calls callback request parameters
    2. the Dial action parameter will contain an endpoint which understands the Dial callback request parameters
    3. both will respond with xml, specifically TwiML.

Effect of Libraries

https://github.com/twilio/twilio-ruby

Twilio ships a client library to ease the use of their API. This allows client developers to set up global state, handle global error conditions and global retry semantics which are consistent across requests, and to hide the url structure and request formats of the endpoints of their API. Their library does not rely on any particular response formatting concerns beyond the global error format. The Twilio library provides limited support for generating appropriate callback endpoints. Specifically, a very thin builder wrapper for constructing TwiML the wrapper is not aware of any url structure, nor does it assist in verifying the structure of the TwiML generated. No support is given for parsing callback requests.

Evolvability Constraints

Twilio's API can evolve independently of clients by adding new endpoints, and by adding additional response data, or adding optional parameters to existing endpoints. Individual calls are locked in their required request parameters. Any change to existing URLs, authentication, AccountSids, or increase in the required parameter set for any call will require a whole API/Client library bump.

With the addition of the client library: If they were to require all clients to use their libraries they could slowly deprecate API versions. By shipping a new version of their API client library, and deprecating older library versions, they can transparently transfer new and existing (upgraded) clients to different URLs and URL structures, as long as the baseline functionality is unchanged. They can even implement new request flows and authentication methods, as long as the new flows are congruent to the existing functionality; i.e. as long as the input parameters to the library methods and responses from the library methods do not change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment