Guessing Game Application Migration from Plivo XML to FlexML
If you have read the Migrating from Plivo to CarrierX Quick Start, you could see that Plivo XML and FlexML are not too much different. Both offer a special syntax to provide instructions, and all you need is to change the representation of these instructions in your code.
But when it comes to a real-case migration from Plivo to CarrierX, users might meet some difficulties.
Let’s see such a migration in details and learn how to solve the issues that arise so that your migrated application worked with CarrierX flawlessly.
Getting Application Source Code
We take the Guessing Game application from Plivo as an example. This sample application answers the call and offers the calling party to play a game: the application generates a random number between 1 and 100 and the calling party must guess what the number is. Additionally, the application has a route that explains the game rules. The calling party has 10 tries to guess the number. You can download the application source code at GitHub.
Once you download the application, you can see that it has the following structure:
Procfile
README.md
guess_game.py
requirements.txt
The only file we need to modify here is guess_game.py
. All the routes used to send requests and responses for our application are here.
Modifying Application Routes
Let’s take a closer look at each of the routes in the file.
The application code file contains four routes:
- index route
- main_menu_response route
- play_game route
- how_to_play route
And one function:
- exit_sequence() function
We will go step by step through each of the routes, check what each of them contains, and learn how to modify these routes and functions to migrate their code to FlexML.
1. index Route
The first route we are going to change is index. The application uses it to greet its users and give them initial instructions on where to start.
We modify the index route like this:
-
The index route uses the
ResponseElement()
class to build the Plivo XML response to the call. In FlexML we do not need it, so we can remove this line. -
We remove the
response.add()
function which builds the response. In FlexML, we will build an XML response instead. -
Finally, we
return
the FlexML formatted string instead of the Plivo XMLResponse()
. In it, we replace Plivo XMLSpeak
element with the corresponding CarrierX FlexMLSay
verb, theGetDigits
element with theGather
verb (dropping the unsupportedretries
attribute).
Plivo XML Python Code
@app.route('/', methods=['POST', 'GET'])
def index():
response = plivoxml.ResponseElement()
response.add(
plivoxml.GetDigitsElement(
action="/main_menu_response",
method="POST",
timeout="4",
num_digits="4",
retries="1",
)
)
response.add(plivoxml.SpeakElement("Hello, welcome to Plivo guessing game app!"))
response.add(plivoxml.SpeakElement("To play the game Press 1"))
response.add(plivoxml.SpeakElement("To learn how to play Press 2"))
response.add(plivoxml.SpeakElement("You can end this call at any time."))
return Response(response.to_string(), mimetype='application/xml')
Corresponding FlexML Python Syntax
@app.route('/', methods=['POST', 'GET'])
def index():
return '''
<Response>
<Gather action="/main_menu_response" method="POST" timeout="4" numDigits="4">
<Say>Hello, welcome to CarrierX guessing game app!</Say>
<Say>To play the game Press 1</Say>
<Say>To learn how to play Press 2</Say>
<Say>You can end this call at any time.</Say>
</Gather>
</Response>'''
2. main_menu_response Route
The main_menu_response route processes the response from the calling party and redirects them to the next instructions set depending on the entered digits.
Thus, we change this route the following way:
-
The main_menu_response route receives the request arguments data from the previous route as
request.form
. In CarrierX FlexML, thePOST
requests send data in JSON format, which you can receive and parse using the Flaskrequest
module. Refer to the code below to see how we replace the definition of thepost_args
variable. -
We remove
plivo.Response()
used to build the Plivo XML response to the call as we are not going to use it. -
Next, we update the URL variable assigned if the calling party pressed 1: we replace
absolute_action_url
in Plivo withaction_url
in CarrierX as FlexML allows using the relative path. We also remove theresponse.add()
function and do not return anything at this step. -
The same way, we update the URL variable assigned if the calling party pressed 2 and also remove the
response.add()
function here. -
Finally, we
return
the FlexML formatted string instead of the Plivo XMLResponse()
. We will use the newaction_url
variables in our return string.
Plivo XML Python Code
@app.route('/main_menu_response', methods=['POST',])
def mm_response():
post_args = request.form
response = plivo.Response()
input_digit = post_args.get('Digits', None)
if input_digit != "1" and input_digit != "2":
return exit_sequence()
else:
if input_digit == "1":
absolute_action_url = url_for('play_game', _external=True)
response.add(plivoxml.RedirectElement(absolute_action_url,method='POST'))
return Response(response.to_string(), mimetype='application/xml')
else:
absolute_action_url = url_for('how_to_play', _external=True)
response.add(plivoxml.RedirectElement(absolute_action_url,method='POST'))
return Response(response.to_string(), mimetype='application/xml')
Corresponding FlexML Python Syntax
@app.route('/main_menu_response', methods=['POST',])
def mm_response():
post_args = request.get_json()
input_digit = post_args.get('Digits', None)
if input_digit != "1" and input_digit != "2":
return exit_sequence()
else:
if input_digit == "1":
action_url = url_for('play_game')
else:
action_url = url_for('how_to_play')
return f'''
<Response>
<Redirect>{action_url}</Redirect>
</Response>'''
3. play_game Route
The play_game route contains the game logic:
- It checks if this is the first time the calling party accesses this route.
- If yes, it “thinks” of a secret number and tells the calling party to guess it.
- If not, it gets the digits pressed by the calling party, checks the number, and counts the number of attempts the calling party has.
- If the number equals the secret number, the application congratulates the calling party and the game is over.
- If not and there are still attempts available, the application tells the calling party if the number entered is smaller or bigger than the secret number, then gives them another chance to guess.
- If not and there are no attempts available, the application informs the calling party about that, tells them the secret number and the game is over.
@app.route('/play_game', methods=['POST',])
def play_game():
if not request.args.get('guesses', None):
secret = random.randint(1, 100)
guesses = 10
response = plivoxml.ResponseElement()
absolute_action_url = url_for('play_game', _external=True,
**{'secret': str(secret),
'guesses': str(guesses)})
response.add(
plivoxml.GetDigitsElement(
action=absolute_action_url,
method="POST",
timeout="10",
num_digits="4",
retries="1",)
.add(
plivoxml.SpeakElement(
"I have thought of a secret number between one and one hundred. You have ten guesses to find it!")
).add(plivoxml.SpeakElement("You can make your guess now."))
)
return Response(response.to_string(), mimetype='application/xml')
else:
secret = int(request.args.get('secret', '0'))
guesses = int(request.args.get('guesses', '0')) - 1
absolute_action_url = url_for('play_game', _external=True,
**{'secret': str(secret),
'guesses': str(guesses)})
input_num = request.form.get('Digits', "0")
response = plivoxml.ResponseElement()
try:
input_num = int(input_num)
except ValueError as e:
print (e)
return exit_sequence()
if input_num == secret:
response.add(plivoxml.SpeakElement("Congratulations! {} is the right number!"
" You have guessed"
" it in {} guesses - your score is {}.".format(secret, 10 - guesses, guesses + 1)))
response.add(plivoxml.WaitElement(None).set_length(2))
response.add(plivoxml.HangupElement())
return Response(response.to_string(), mimetype='application/xml')
else:
if input_num > secret:
answer = "Sorry, you guessed %d. The secret is lesser."
else:
answer = "Sorry, you guessed %d. The secret is greater."
response.add(plivoxml.SpeakElement(answer+input_num))
if guesses > 0:
response.add(
plivoxml.GetDigitsElement(action=absolute_action_url, method='POST',timeout='10',num_digits='4',retries='1').add(
plivoxml.SpeakElement("You have {} guesses remaining! Guess again!".format(guesses))))
else:
response.add(plivoxml.WaitElement (None).set_length (1))
response.add(plivoxml.SpeakElement('Sorry, you dont have any remaining guesses. The secret was {}' .format(secret)))
response.add(plivoxml.HangupElement())
return Response(response.to_string(), mimetype='application/xml')
As the route code is quite lengthy, we will split it into several parts and see what we need to change in each of these parts.
Route First-time Access
When the calling party accesses the play_game.py route for the first time, the application “thinks” of a secret number (generates a random integer between 1 and 100), informs the calling party and collects the entered digits. After that, it runs the route from the beginning once again, this time with the entered digits and available attempts as arguments.
from xml.sax.saxutils import escape
We change the first part of the route the following way:
-
The
play_game
route uses theResponseElement()
class to build the Plivo XML response to the call. In FlexML we do not need it, so we can remove this line. -
We replace
absolute_action_url
withaction_url
containing a relative URL and make it escaped with the help ofescape()
. -
We remove the
response.add()
function which builds the response. In FlexML, we will build an XML response instead. -
Finally, we
return
the FlexML formatted string instead of the Plivo XMLResponse()
. In it, we replace Plivo XMLSpeak
element with the corresponding CarrierX FlexMLSay
verb, theGetDigits
element with theGather
verb (dropping the unsupportedretries
attribute).
Plivo XML Python Code
@app.route('/play_game', methods=['POST',])
def play_game():
if not request.args.get('guesses', None):
secret = random.randint(1, 100)
guesses = 10
response = plivoxml.ResponseElement()
absolute_action_url = url_for('play_game', _external=True,
**{'secret': str(secret),
'guesses': str(guesses)})
response.add(
plivoxml.GetDigitsElement(
action=absolute_action_url,
method="POST",
timeout="10",
num_digits="4",
retries="1",)
.add(
plivoxml.SpeakElement(
"I have thought of a secret number between one and one hundred. You have ten guesses to find it!")
).add(plivoxml.SpeakElement("You can make your guess now."))
)
return Response(response.to_string(), mimetype='application/xml')
Corresponding FlexML Python Syntax
@app.route('/play_game', methods=['POST'])
def play_game():
if not request.args.get('guesses', None):
secret = random.randint(1, 100)
guesses = 10
action_url = escape(url_for('play_game',
**{'secret': str(secret),
'guesses': str(guesses)}))
return f'''
<Response>
<Gather action="{action_url}" method="POST" timeout="10" numDigits="4">
<Say>I have thought of a secret number between one and one hundred. You have ten guesses to find it!</Say>
<Say>You can make your guess now.</Say>
</Gather>
</Response>'''
Correct Guess
If this is not the first time the calling party accesses the play_game.py route and they have already entered some digits, the application receives the digits pressed by the calling party. It checks the number, and counts the number of attempts the calling party has.
If the number equals the secret number, the application congratulates the calling party and hangs up after a two-second pause. The game is over.
We change this part of the play_game.py route the following way:
-
First, we replace
absolute_action_url
withaction_url
containing a relative URL and make it escaped with the help ofescape()
. -
The play_game.py route receives the request arguments data from the
POST
request asrequest.form
. In CarrierX FlexML, thePOST
requests send data in JSON format, which you can receive and parse using the Flaskrequest
module. Refer to the code below to see how we replace the definition of theinput_num
variable. -
The route uses the
ResponseElement()
class to build the Plivo XML response to the call. In FlexML we do not need it, so we can remove this line. -
We remove the
response.add()
function which builds the response. In FlexML, we will build an XML response instead. -
Finally, we
return
the FlexML formatted string instead of the Plivo XMLResponse()
. In it, we replace Plivo XMLSpeak
element with the corresponding CarrierX FlexMLSay
verb, theWait
element with thePause
verb.
Plivo XML Python Code
else:
secret = int(request.args.get('secret', '0'))
guesses = int(request.args.get('guesses', '0')) - 1
absolute_action_url = url_for('play_game', _external=True,
**{'secret': str(secret),
'guesses': str(guesses)})
input_num = request.form.get('Digits', "0")
response = plivoxml.ResponseElement()
try:
input_num = int(input_num)
except ValueError as e:
print (e)
return exit_sequence()
if input_num == secret:
response.add(plivoxml.SpeakElement("Congratulations! {} is the right number!"
" You have guessed"
" it in {} guesses - your score is {}.".format(secret, 10 - guesses, guesses + 1)))
response.add(plivoxml.WaitElement(None).set_length(2))
response.add(plivoxml.HangupElement())
return Response(response.to_string(), mimetype='application/xml')
Corresponding FlexML Python Syntax
else:
secret = int(request.args.get('secret', '0'))
guesses = int(request.args.get('guesses', '0')) - 1
action_url = escape(url_for('play_game',
**{'secret': str(secret),
'guesses': str(guesses)}))
data = request.get_json()
input_num = data.get('Digits', '0')
try:
input_num = int(input_num)
except ValueError as e:
print (e)
return exit_sequence()
if input_num == secret:
return f'''
<Response>
<Say>Congratulations! {secret} is the right number!</Say>
<Say>You have guessed it in {10 - guesses} guesses - your score is {guesses + 1}.</Say>
<Pause length="2"/>
<Hangup/>
</Response>'''
Wrong Guesses
When the number is bigger or smaller than the secret number, the application checks if there are any attempts available.
- If yes, the application tells the calling party if the number entered is smaller or bigger than the secret number, then gives them another chance to guess.
- If not, the application informs the calling party about that, tells them the secret number and the game is over.
We change this part of the play_game.py route the following way:
-
First, we modify the
answer
variable. It will now contain FlexML syntax with theSay
verb. -
We will do the same for the
else
condition which also contains theanswer
variable declaration. -
We remove the
response.add()
function which builds the response. In FlexML, we will use theanswer
variable as a part of our response. -
We replace the
response.add()
function in theif guesses > 0
condition with the newly introducedguesses_remain
variable. We will use this variable as a part of our response. It contains the FlexML formatted string in which we replace Plivo XMLGetDigits
element with the corresponding CarrierX FlexMLGather
verb (dropping the unsupportedretries
attribute), theSpeak
element with theSay
verb. We also use theaction_url
from the previous step for theGather
verb. -
We replace the
response.add()
function in the nextelse
condition with theguesses_remain
variable as well. It contains the FlexML formatted string in which we replace Plivo XMLWait
element with the corresponding CarrierX FlexMLPause
verb, theSpeak
element with theSay
verb. -
Finally, we
return
the FlexML formatted string instead of the Plivo XMLResponse()
. In it, we use our resulting values for theanswer
andguesses_remain
variables.
Plivo XML Python Code
else:
if input_num > secret:
answer = "Sorry, you guessed %d. The secret is lesser."
else:
answer = "Sorry, you guessed %d. The secret is greater."
response.add(plivoxml.SpeakElement(answer+input_num))
if guesses > 0:
response.add(
plivoxml.GetDigitsElement(action=absolute_action_url, method='POST',timeout='10',num_digits='4',retries='1').add(
plivoxml.SpeakElement("You have {} guesses remaining! Guess again!".format(guesses))))
else:
response.add(plivoxml.WaitElement (None).set_length (1))
response.add(plivoxml.SpeakElement('Sorry, you dont have any remaining guesses. The secret was {}' .format(secret)))
response.add(plivoxml.HangupElement())
return Response(response.to_string(), mimetype='application/xml')
Corresponding FlexML Python Syntax
else:
if input_num > secret:
answer = f'<Say>Sorry, you guessed {input_num}. The secret is lesser.</Say>'
else:
answer = f'<Say>Sorry, you guessed {input_num}. The secret is greater.</Say>'
if guesses > 0:
guesses_remain = f'''
<Gather action="{action_url}" method="POST" timeout="10" numDigits="4">
<Say>You have {guesses} guesses remaining! Guess again!</Say>
</Gather>'''
else:
guesses_remain = f'''
<Pause length="1"/>
<Say>Sorry, you don't have any remaining guesses. The secret was {secret}</Say>
<Hangup/>'''
return f'''
<Response>
{answer}
{guesses_remain}
</Response>'''
@app.route('/play_game', methods=['POST'])
def play_game():
if not request.args.get('guesses', None):
secret = random.randint(1, 100)
guesses = 10
action_url = escape(url_for('play_game',
**{'secret': str(secret),
'guesses': str(guesses)}))
return f'''
<Response>
<Gather action="{action_url}" method="POST" timeout="10" numDigits="4">
<Say>I have thought of a secret number between one and one hundred. You have ten guesses to find it!</Say>
<Say>You can make your guess now.</Say>
</Gather>
</Response>'''
else:
secret = int(request.args.get('secret', '0'))
guesses = int(request.args.get('guesses', '0')) - 1
action_url = escape(url_for('play_game',
**{'secret': str(secret),
'guesses': str(guesses)}))
data = request.get_json()
input_num = data.get('Digits', '0')
try:
input_num = int(input_num)
except ValueError as e:
print (e)
return exit_sequence()
if input_num == secret:
return f'''
<Response>
<Say>Congratulations! {secret} is the right number!</Say>
<Say>You have guessed it in {10 - guesses} guesses - your score is {guesses + 1}.</Say>
<Pause length="2"/>
<Hangup/>
</Response>'''
else:
if input_num > secret:
answer = f'<Say>Sorry, you guessed {input_num}. The secret is lesser.</Say>'
else:
answer = f'<Say>Sorry, you guessed {input_num}. The secret is greater.</Say>'
if guesses > 0:
guesses_remain = f'''
<Gather action="{action_url}" method="POST" timeout="10" numDigits="4">
<Say>You have {guesses} guesses remaining! Guess again!</Say>
</Gather>'''
else:
guesses_remain = f'''
<Pause length="1"/>
<Say>Sorry, you don't have any remaining guesses. The secret was {secret}</Say>
<Hangup/>'''
return f'''
<Response>
{answer}
{guesses_remain}
</Response>'''
4. how_to_play Route
The how_to_play route plays back the instructions explaining how to play the guessing game.
We change this route the following way:
-
The how_to_play route uses the
ResponseElement()
class to build the Plivo XML response to the call. In FlexML we do not need it, so we can remove this line. -
Next, we update the URL variable used to redirect the calling party after the application finishes to read the instructions: we replace
abs_red_url
in Plivo withred_url
in CarrierX as FlexML allows using the relative path. -
We remove the
response.add()
function which builds the response. In FlexML, we will build an XML response instead. -
Finally, we
return
the FlexML formatted string instead of the Plivo XMLResponse()
. In it, we replace Plivo XMLSpeak
element with the corresponding CarrierX FlexMLSay
verb, theWait
element with thePause
verb.
Plivo XML Python Code
@app.route('/how_to_play', methods=['POST'])
def how_to_play():
response = plivoxml.ResponseElement()
response.add(plivoxml.SpeakElement('I will think of a secret number that you will have to guess.'))
response.add(plivoxml.SpeakElement('The number will be between one and one hundred.'))
response.add(plivoxml.SpeakElement('To make your guess, just dial the digits and end with the hash sign.'))
response.add(plivoxml.SpeakElement('For each wrong guess, I will tell you if you guessed lesser of greater.'))
response.add(plivoxml.SpeakElement('You will have a maximum of ten chances to guess the number.'))
response.add(plivoxml.WaitElement(None).set_length(6))
response.add(plivoxml.SpeakElement('You will now be transferred to the main menu.'))
abs_red_url = url_for('index', _external=True)
response.add(plivoxml.RedirectElement(abs_red_url))
return Response(response.to_string(), mimetype='application/xml')
Corresponding FlexML Python Syntax
@app.route('/how_to_play', methods=['POST'])
def how_to_play():
red_url = url_for('index')
return f'''
<Response>
<Say>I will think of a secret number that you will have to guess.</Say>
<Say>The number will be between one and one hundred.</Say>
<Say>To make your guess, just dial the digits and end with the hash sign.</Say>
<Say>For each wrong guess, I will tell you if you guessed lesser of greater.</Say>
<Say>You will have a maximum of ten chances to guess the number.</Say>
<Pause length="6"/>
<Say>You will now be transferred to the main menu.</Say>
<Redirect>{red_url}</Redirect>
</Response>'''
5. exit_sequence() Function
The application uses the exit_sequence() function to reject the call if the calling party enters anything but a digit. The main_menu_response
and play_game
routes use this function.
We change this function the following way:
-
The exit_sequence() function uses the
ResponseElement()
class to build the Plivo XML response to the call. In FlexML we do not need it, so we can remove this line. We also remove theresponse.add()
function which builds the response. In FlexML, we will build an XML response instead. -
We
return
the FlexML formatted string instead of the Plivo XMLResponse()
. In it, we replace Plivo XMLSpeak
element with the corresponding CarrierX FlexMLSay
verb, theHangup
element with theReject
verb (dropping the unsupportedschedule
attribute).
Plivo XML Python Code
def exit_sequence(msg="Oops! There was an error!"):
response = plivoxml.ResponseElement()
response.add(plivoxml.HangupElement(schedule=10, reason='rejected'))
response.add(
plivoxml.SpeakElement('We did not receive a valid response. We will hangup now.'))
return Response(response.to_string(), mimetype='application/xml')
Corresponding FlexML Python Syntax
def exit_sequence(msg="Oops! There was an error!"):
return '''
<Response>
<Say>We did not receive a valid response. We will hangup now.</Say>
<Reject reason="rejected"/>
</Response>'''
Now that we modified all the routes, we can safely remove the Plivo library import declaration from the beginning of the guess_game.py
file:
from plivo import plivoxml
from flask import Flask, url_for, request
import random
import os
from xml.sax.saxutils import escape
app = Flask(__name__)
@app.route('/', methods=['POST', 'GET'])
def index():
return '''
<Response>
<Gather action="/main_menu_response" method="POST" timeout="4" numDigits="4">
<Say>Hello, welcome to CarrierX guessing game app!</Say>
<Say>To play the game Press 1</Say>
<Say>To learn how to play Press 2</Say>
<Say>You can end this call at any time.</Say>
</Gather>
</Response>'''
def exit_sequence(msg="Oops! There was an error!"):
return '''
<Response>
<Say>We did not receive a valid response. We will hangup now.</Say>
<Reject reason="rejected"/>
</Response>'''
@app.route('/main_menu_response', methods=['POST',])
def mm_response():
post_args = request.get_json()
print (post_args)
print (request.data)
input_digit = post_args.get('Digits', None)
if input_digit != "1" and input_digit != "2":
return exit_sequence()
else:
if input_digit == "1":
action_url = url_for('play_game')
else:
action_url = url_for('how_to_play')
return f'''
<Response>
<Redirect>{action_url}</Redirect>
</Response>'''
@app.route('/play_game', methods=['POST'])
def play_game():
if not request.args.get('guesses', None):
secret = random.randint(1, 100)
guesses = 10
action_url = escape(url_for('play_game',
**{'secret': str(secret),
'guesses': str(guesses)}))
return f'''
<Response>
<Gather action="{action_url}" method="POST" timeout="10" numDigits="4">
<Say>I have thought of a secret number between one and one hundred. You have ten guesses to find it!</Say>
<Say>You can make your guess now.</Say>
</Gather>
</Response>'''
else:
secret = int(request.args.get('secret', '0'))
guesses = int(request.args.get('guesses', '0')) - 1
action_url = escape(url_for('play_game',
**{'secret': str(secret),
'guesses': str(guesses)}))
data = request.get_json()
input_num = data.get('Digits', '0')
try:
input_num = int(input_num)
except ValueError as e:
print (e)
return exit_sequence()
if input_num == secret:
return f'''
<Response>
<Say>Congratulations! {secret} is the right number!</Say>
<Say>You have guessed it in {10 - guesses} guesses - your score is {guesses + 1}.</Say>
<Pause length="2"/>
<Hangup/>
</Response>'''
else:
if input_num > secret:
answer = f'<Say>Sorry, you guessed {input_num}. The secret is lesser.</Say>'
else:
answer = f'<Say>Sorry, you guessed {input_num}. The secret is greater.</Say>'
if guesses > 0:
guesses_remain = f'''
<Gather action="{action_url}" method="POST" timeout="10" numDigits="4">
<Say>You have {guesses} guesses remaining! Guess again!</Say>
</Gather>'''
else:
guesses_remain = f'''
<Pause length="1"/>
<Say>Sorry, you don't have any remaining guesses. The secret was {secret}</Say>
<Hangup/>'''
return f'''
<Response>
{answer}
{guesses_remain}
</Response>'''
@app.route('/how_to_play', methods=['POST'])
def how_to_play():
red_url = url_for('index')
print(red_url)
return f'''
<Response>
<Say>I will think of a secret number that you will have to guess.</Say>
<Say>The number will be between one and one hundred.</Say>
<Say>To make your guess, just dial the digits and end with the hash sign.</Say>
<Say>For each wrong guess, I will tell you if you guessed lesser of greater.</Say>
<Say>You will have a maximum of ten chances to guess the number.</Say>
<Pause length="6"/>
<Say>You will now be transferred to the main menu.</Say>
<Redirect>{red_url}</Redirect>
</Response>'''
if __name__ == "__main__":
port = int(os.environ.get('PORT', 5000))
app.debug = True
app.run(host='0.0.0.0', port=port)
You can also remove the importing of Plivo modules from the requirements.txt
file.
Finishing Migration
Now let’s test our application! You can run your local Flask server through terminal using the following command that will serve the created application to the incoming requests.
FLASK_APP=guess_game.py flask run
Now your application is running, but it is not visible to the outside world. We need to expose the localhost route publicly over the Internet so that your endpoint could access and load the FlexML instructions. To do this, we can use the free ngrok tool. If you choose to use ngrok, follow the instructions on their website to download it. Alternatively, you may expose the URL any other way you choose.
Once your Flask server is running, your terminal will list the port it is running on. Expose this port by running the following command through terminal. Make sure to replace 5000
(which is the Flask default port) with the port that your Flask server is running on.
./ngrok http 5000
When ngrok is run successfully, it will open a new terminal tab that will show you the http
and https
URLs that make the application publicly available over the Internet.
Add the https
ngrok link (in our sample it is https://d4d66ed41d49.ngrok.io/
, as we chose /
to be our default route) to either a FlexML endpoint or a DID associated with a FlexML endpoint. Refer to the FlexML Endpoint quick start guide to learn how.
After that, call the associated DID to check how the application works.
Further Reading
You have successfully migrated the Guessing Game application from Plivo XML to FlexML!
Refer to the following pages to learn more about FlexML verbs and how to use them, and about ways to set up a FlexML endpoint:
Use our Migrating from Plivo XML to CarrierX Quick Start to learn more about other difficulties you can meet while migrating from Plivo XML to CarrierX and the ways to solve these issues.
Read other instructions on real-case migrations from Plivo XML to CarrierX here:
Refer to our other quick start guides for instructions on how to work with CarrierX: