April 23, 2015

Telephonist: State Machines for Twilio

After a couple months of work, I’ve finally got the library I’ve been working toward for Twilio, and I’m calling it “Telephonist”. You can read all about it over on Github, but here’s a taste:

defmodule CustomCallFlow do
  use Telephonist.StateMachine, initial_state: :choose_language

  state :choose_language, twilio, options do
    say "#{options[:error]}" # say any error, if present
    gather timeout: 10 do
      say "For English, press 1"
      say "Para español, presione 2"
    end
  end

  state :english, twilio, options do
    say "Proceeding in English..."
  end

  state :spanish, twilio, options do
    say "Procediendo en español..."
  end

  # If the user pressed "1" on their keypad, transition to English state
  def transition(:choose_language, %{Digits: "1"} = twilio, options) do
    state :english, twilio, options
  end

  # If the user pressed "2" on their keypad, transition to Spanish state
  def transition(:choose_language, %{Digits: "2"} = twilio, options) do
    state :spanish, twilio, options
  end

  # If neither of the above are true, append an error to the options and
  # remain on the current state
  def transition(:choose_language, twilio, options) do
    options = Map.put(options, :error, "You pressed an invalid digit. Please try again.")
    state :choose_language, twilio, options
  end
end

Use the state machine from your web framework like this:

# The web framework shown here is pseudo-code
def index(conn, twilio) do
  options = %{} # Whatever I want to be able to use in my states and transitions
  state = Telephonist.CallProcessor.process(CustomCallFlow, twilio, options)
  render conn, xml: state.twiml
end

Which will render some nice TwiML:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather timeout="10">
    <Say>For English, press 1</Say>
    <Say>Para español, presione 2</Say>
  </Gather>
</Response>

Unlike my previous attempt at this, Telephonist has no dependency on any ORM layer, is very concurrent, and produces code that is easy to maintain.

Telephonist will be released on Hex soon, (once I get the documentation finished) and in the future, I may create a Ruby version.

Did You Enjoy This Post?