Server Notifications Application Migration from Twilio to CarrierX
If you have read the Migrating from Twilio to CarrierX Quick Start, you could see that both Twilio and CarrierX provide similar means, which allow their users to send voice calls and text messages, 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 Twilio 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 Server Notifications application from Twilio as an example. This sample application sends a text message to the server administrator phone number with the details about the server problems. You can download the application source code at GitHub.
Once you download the application, you can see that it has the following structure:
[config]
[twilio_notifications]
[twilio_sample_project]
.coveragerc
.env_example
.gitignore
.travis.yml
LICENSE
README.md
manage.py
requirements.txt
The twilio_notifications
folder holds the files we are going to modify. Here is its structure:
[tests]
__init__.py
middleware.py
We need to modify the middleware.py
file. All the functions used to send requests for our application are here.
Modifying Files
The middleware.py
file contains the following functions and classes:
- the load_twilio_config() function helps load the application configuration variables required for the access to the API and the application correct work;
- the MessageClient class forms the request to the API with the help of Twilio client library;
- the TwilioNotificationsMiddleware class loads the list of administrators and their phones, get the server exception data, and prepares the request with the previously defined MessageClient class.
Let’s see what, where, and how should be modified.
I. load_twilio_config() Function
We modify the load_twilio_config() function like this:
-
We replace Twilio variables necessary to send requests to the API with CarrierX ones. Instead of using three variables (
twilio_account_sid
,twilio_auth_token
, andtwilio_number
), we now use only two (carrierx_token
andcarrierx_phone_number
), which values we get from the application environment. -
The
if
condition took the three variables as its arguments, we replace them with the two new. -
The
return
statement also accepted all the three variables. We do not need them now, let’s also replace them with CarrierX ones.
Twilio Python Code
def load_twilio_config():
twilio_account_sid = os.getenv('TWILIO_ACCOUNT_SID')
twilio_auth_token = os.getenv('TWILIO_AUTH_TOKEN')
twilio_number = os.getenv('TWILIO_NUMBER')
if not all([twilio_account_sid, twilio_auth_token, twilio_number]):
raise ImproperlyConfigured(NOT_CONFIGURED_MESSAGE)
return (twilio_number, twilio_account_sid, twilio_auth_token)
Corresponding CarrierX Python Syntax
def load_twilio_config():
carrierx_token = os.getenv('CARRIERX_TOKEN')
carrierx_phone_number = os.getenv('CARRIERX_PHONE_NUMBER')
if not all([carrierx_token, carrierx_phone_number]):
raise ImproperlyConfigured(NOT_CONFIGURED_MESSAGE)
return (carrierx_token, carrierx_phone_number)
II. MessageClient Class
The MessageClient class uses Twilio library which forms the request to the API. We are not using it, so we remove the MessageClient class and rearrange this section like this:
-
The invoking of the
load_twilio_config()
function in theMessageClient
class moves to thesend_message()
function. We remove the rest of the code for theMessageClient
class. -
The
send_message()
function now goes a level higher, accepts two arguments (body
andto
), and inside it we form the request to the CarrierX Core API with the help of the Send Message method.
Twilio Python Code
class MessageClient:
def __init__(self):
(
twilio_number,
twilio_account_sid,
twilio_auth_token,
) = load_twilio_config()
self.twilio_number = twilio_number
self.twilio_client = Client(twilio_account_sid, twilio_auth_token)
def send_message(self, body, to):
self.twilio_client.messages.create(
body=body,
to=to,
from_=self.twilio_number,
)
Corresponding CarrierX Python Syntax
def send_message(body, to):
(
carrierx_token,
carrierx_phone_number,
) = load_twilio_config()
url = "https://api.carrierx.com/core/v2/sms/messages"
headers = {'Authorization': f'Bearer {carrierx_token}', 'Content-Type':'application/json'}
payload = {"from_did": carrierx_phone_number, "to_did": to, "message": body}
request_details = requests.post(url, data=json.dumps(payload), headers=headers)
For the POST
request correct work, we need to import the requests
and json
Python modules. We add this to the beginning of the middleware.py
file:
import requests, json
III. TwilioNotificationsMiddleware Class
We modify the TwilioNotificationsMiddleware class section like this:
-
Remove the use of the no longer existing
MessageClient
class. -
Edit the
send_message()
function call according to its changes in the previous section.
Twilio Python Code
class TwilioNotificationsMiddleware:
def __init__(self, get_response):
self.administrators = load_admins_file()
self.client = MessageClient()
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_exception(self, request, exception):
message_to_send = MESSAGE.format(exception)
for admin in self.administrators:
self.client.send_message(message_to_send, admin['phone_number'])
return None
Corresponding CarrierX Python Syntax
class TwilioNotificationsMiddleware:
def __init__(self, get_response):
self.administrators = load_admins_file()
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_exception(self, request, exception):
message_to_send = MESSAGE.format(exception)
for admin in self.administrators:
send_message(message_to_send, admin['phone_number'])
return None
IV. Configuration Files
As you could notice, we used the CARRIERX_TOKEN
and CARRIERX_PHONE_NUMBER
variables in our migrated code. They are stored in the .env
file in the application route. Change their values with the ones from CarrierX. These values can be taken in your portal account profile. Refer to the Security Token and Rent Phone Number Quick Starts for more information on where to get the token and the phone number.
Add these variables with their values to the .env
file:
export CARRIERX_TOKEN=5ebc03d6-8b2b-44ad-bf65-72d4f1491dda
export CARRIERX_PHONE_NUMBER=15162065515
Do not forget to change the phone number you are going to send the message to in the administrators.json
file.
Finishing Migration
Now that we modified the routes, we can safely remove the Twilio libraries import declaration from the beginning of the middleware.py
file:
from twilio.rest import Client
import requests, json
import os
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from dotenv import load_dotenv
dotenv_path = settings.PROJECT_PATH / '.env'
load_dotenv(dotenv_path=dotenv_path)
MESSAGE = """[This is a test] ALERT! It appears the server is having issues.
Exception: {0}"""
NOT_CONFIGURED_MESSAGE = (
"Required enviroment variables "
"CARRIERX_TOKEN or CARRIERX_PHONE_NUMBER missing."
)
def load_admins_file():
admins_json_path = settings.PROJECT_PATH / 'config' / 'administrators.json'
return json.loads(admins_json_path.read_text())
def load_twilio_config():
carrierx_token = os.getenv('CARRIERX_TOKEN')
carrierx_phone_number = os.getenv('CARRIERX_PHONE_NUMBER')
if not all([carrierx_token, carrierx_phone_number]):
raise ImproperlyConfigured(NOT_CONFIGURED_MESSAGE)
return (carrierx_token, carrierx_phone_number)
def send_message(body, to):
(
carrierx_token,
carrierx_phone_number,
) = load_twilio_config()
url = "https://api.carrierx.com/core/v2/sms/messages"
headers = {'Authorization': f'Bearer {carrierx_token}', 'Content-Type':'application/json'}
payload = {"from_did": carrierx_phone_number, "to_did": to, "message": body}
request_details = requests.post(url, data=json.dumps(payload), headers=headers)
class TwilioNotificationsMiddleware:
def __init__(self, get_response):
self.administrators = load_admins_file()
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_exception(self, request, exception):
message_to_send = MESSAGE.format(exception)
for admin in self.administrators:
send_message(message_to_send, admin['phone_number'])
return None
You can also remove the importing of Twilio modules from the requirements.txt
file.
Follow the instructions from the application GitHub page to run the application. Then open the application error
page in your browser and the application will send a server error message to the phone number you specified in the administrators.json
file.
Further Reading
You have successfully migrated the Server Notifications application from Twilio to CarrierX!
Refer to the following page to learn more about CarrierX API:
Use our Migrating from Twilio to CarrierX Quick Start to learn more about other difficulties you can meet while migrating from Twilio to CarrierX and the ways to solve these issues.
Read other instructions on real-case migrations from Twilio to CarrierX here:
- Send SMS During Calls Application Migration
- Lead Alerts Application Migration
- Call Forwarding Application Migration
- Automated Survey Application Migration
Refer to our other quick start guides for instructions on how to work with CarrierX: