This code chunk utilizes Twilio to send SMS messages to users when an automatic payment is coming up.
using System.Diagnostics;
using Core.Accessors;
using Core.Models;
using Twilio;
using Twilio.Exceptions;
using Twilio.Rest.Api.V2010.Account;
namespace Accessors
{
public class TextMessageAccessor : ITextMessageAccessor
{
public bool Send(PhoneNumber to, string body)
{
var accountSid = "AC9e977e44167ba6b169d6884c96a9903c";
var authToken = "b96004eaed62d0eb9ba571a95048776d";
TwilioClient.Init(accountSid, authToken);
try
{
var message = MessageResource.Create(
to: new Twilio.Types.PhoneNumber(to.Number),
from: "+15312016725",
body: body);
return true;
}
catch (ApiException e)
{
Debug.WriteLine(e.Message);
Debug.WriteLine($"Twilio Error {e.Code} - {e.MoreInfo}");
return false;
}
}
}
}
This code uses the Twilio API to send automatic text message notifications to users when a payment is coming
up. It belongs in the Accessor layer, and it only interacts with the Core layer directly below it. It uses
credentials given by my account on Twilio to send a text message to the phone number gathered during registration.
First, this method implements
ITextMessageAccessor
, and uses a Unity DI container to achieve constructor injection. This code demonstrates adaptation to change.
Our initial schema did not account for text message notifications, but it was designed such that this type
of notification would be possible. We standardized the representation of
PhoneNumber
so it could be used by text message notification APIs by accessing a property directly without writing error-prone
string manipulation code.
The structure of the workflow made it easy to integrate a third-party API with our home-grown code. It demonstrates
good use of the library by researching the custom exceptions that belong to the API and catching these exceptions
where the library is used, the most logical place, since this feature is not client-facing in the web app.
I chose to not propagate these exceptions to the Engine level so that I could use Twilio's custom exceptions
without importing the library again in another spot.
ApiException
is a custom Twilio exception that provides better error documentation than one a developer using it would
have implemented, so it prevents reinventing the wheel.
I avoided reinventing the wheel and stayed consistent with our existing notification workflow by using Twilio's
C# NuGet package to call
messageResource.Create()
instead of formatting my own HTTP request to Twilio's endpoint in the Web layer, which the JavaScript
documentation suggests. The final reason I preferred to write this on the C# side relates to volatility-based
decomposition - client-facing code tends to change more frequently and more quickly than back-end code, and
because this code is not volatile, it should be encapsulated with other non-volatile code. Finally, this
code demonstrates consistency with the remainder of the code base. The
ITextMessageAccessor
and the
ISmtpEmailServerAccessor
both contain a
Send
method, and the
TextNotificationProcessing Engine
and the
EmailNotificationProcessingEngine
have similar workflows that follow from this acccessor. If a developer at Nelnet were to take on our project
after handoff, it would be easy for them to navigate the structure of both notification workflows.