#twilio #development

Twilio meets Chuck Norris (and survives!)

I have always had a soft spot for Chuck Norris. I used to own a silver Ford Ranger called “Truck Norris” and my very first attempt at consuming an API was with The Internet Chuck Norris Database and was called Chuck Norris Facts.

I have been wanting to play with a Twilio Api and thought “Why not combine it with Chuck Norris?”.

Why not indeed!!!


A quick note on my setup: I am using Windows 10 with Visual Studio 2017 Community edition. My project is a Dotnet Core 2.0 solution.

For this project I decided to try out ChuckNorris.io and combine it with Twilio’s “Programmable SMS” service.

I haven’t used Twilio before, but my co-host at the MK.NET meetup, Marcos is an evangelist for them. I used to work for a telecommunications company too so it definitely piqued my interest.

I started off by signing up for a free account with Twilio. You can do that here.

With the free account you will get a single telephone number to play around with, so go ahead and add one from the Twilio Console (click the “Buy a number” link).

image showing the twilio dashboard

Once I registered, I received a welcome email from Twilio with links to documentation. I clicked on the “sample code” one, picked a tutorial on SMS but this is where I started to come undone.

The tutorial went straight to how to integrate Twilio into a solution with a complete repository on github. I, personally, felt that the tutorial became too specific too quickly and I was overwhelmed.

I recalled that there was a blog about getting Twilio up and running in 30 seconds, so I decided to try following that. I couldn’t get it to work… (The article was dated November 2016, so it is reasonable that it could be out of date).

I then decided to try to query the API using Postman (an HTTP client). The first few API methods I tried worked fine (e.g. query account), then I tried to use the API to send an SMS. I kept getting the error “‘From’ telephone number was required”. Upon googling I found a StackOverflow post on the same issue. I raised a ticket with Twilio and took a break.

image showing the postman error

Fair dues to Twilio, they got back within an hour (and on a Sunday!) So big tick for support!

It turns out that you can’t send json to the API, so in Postman you will need to use form data - check out this post on how to do it.


By this point I had since returned to the Twilio documentation and found the blazingly obvious quickstart menu option.

I’m going to put this oversight down to a long and stressful week at work and my brain having gone on strike.

Finally I had some working code.

[Route("api/[controller]")]
public class MessageController : TwilioController
{
    [HttpPost]
    public IActionResult Post([FromBody] MessageViewModel messageViewModel)
    {
                       const string accountSid =  "your_account_sid";
       const string authToken = "your_auth_token";
       TwilioClient.Init(accountSid, authToken);

       var to = new PhoneNumber("+123456789");
       var message = MessageResource.Create(
                    to,
                    from: new PhoneNumber("+123456987"),
                    body: "This is the ship that made the Kessel Run in fourteen parsecs?");

      return TwiML(messagingResponse);
    }
}
public class MessageViewModel
{
   public string To { get; set; }
   public string Body { get; set; }

}



image showing the postman request

image showing the the incoming text

gif of girl dancing


Right now I’m feeling pretty pleased with myself; I have sent a text message! Hmmmm, maybe not that impressive. What happens when I respond to this text message? Zilch.

This is where Twilio webhooks come in. Twilio has some pretty good documentation explaining this, so take a look at this guide about using ngrok (the post also explains what ngrok is - so read that rather than me try to paraphrase).

I followed this guide to the letter… it didn’t work for me. How did I not rage-quit?!? Perseverance, I tell you!

If it works for you, that’s great, but here’s what I had to do:

  1. Download ngrok, then move the executable to a folder called ngrok in C:\Program Files
  2. Add “C:\Program Files\ngrok” to the PATH - I added it to both the system and the user path to be on the safe side. This is done by clicking the Windows button, typing “Environment” and the selecting “Edit the system Environment variables”. Then editing the PATH on the next screen.
  3. Download and install the ngrok extension for Visual Studio
  4. Run Visual Studio as Administrator Only then could I click on tools tab in Visual Studio and start an ngrok tunnel.
    After I had ngrok running, I really started to make progress and I could start to see how truly powerful the Twilio API was.

By just adding the ngrok url, plus the route to my controller, to the the webhook on my Twilio number, I could trigger my app.

image of twilio webhook

[Route("api/[controller]")]
public class MessageResponseController : TwilioController
{
    [HttpPost]
    public TwiMLResult Post()
    {
        var messagingResponse = new MessagingResponse();
        messagingResponse.Message("Hello from my app");

        return TwiML(messagingResponse);
    }
}


Twilio will also send you a fair bit of information with the call to your API, which can be found here.

I created a C# model, TwimlResponseMessage, in my project to map the API response too - I didn’t map all of the response, just the parts I thought I might need.

[Route("api/[controller]")]
public class MessageResponseController : TwilioController
{
    [HttpPost]
    public TwiMLResult Post(TwimlResponseMessage response)
    {
        var messagingResponse = new MessagingResponse();
        messagingResponse.Message("Hello from my app");

        return TwiML(messagingResponse);
    }
}
public class TwimlResponseMessage
{
    public string MessageSid { get; set; }
    public string AccountSid { get; set; }
    public string From { get; set; }
    public string To { get; set; }
    public string Body { get; set; }
    public int NumMedia { get; set; }
    public string FromCountry { get; set; }
}


Getting the body of the SMS that was sent to Twilio, is a key part in implementing the next part of my plan.

ChuckNorris.io will either send random jokes out or jokes based on a selected category. I wanted my user to be able to text the category of joke they wanted to my sevice and for it to return the relevent joke.

To do this, I started to break my code out into services, making them more testable (when I get round to writing the tests - bad Layla).

I utilised C#’s asynchronous Http methods when calling the ChuckNorris.io API. This meant that I had to update all the methods above to be asynchronous too.

private async Task<ChuckNorrisResponse> GetNewJokeAsync()
{
    ChuckNorrisResponse joke = null;

    using (var httpClient = new HttpClient())
    {

        try
        {
            var apiEndPoint = "https://api.chucknorris.io/jokes/random";;
            httpClient.BaseAddress = new Uri(apiEndPoint);
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            var responseMessage = await 
                httpClient
                    .GetAsync(apiEndPoint);

            if (responseMessage.IsSuccessStatusCode)
            {
                joke = await 
                    responseMessage
                        .Content
                        .ReadAsAsync<ChuckNorrisResponse>();
            }

        }
        catch (Exception e)
        {
            LogHelper.Error($"JokeService:GetNewJoke Exceptioned with {e.Message}");
        }
    }
    return joke;
}
public class ChuckNorrisResponse
{
    public List<string> Category { get; set; }
    [JsonProperty("icon_url")]
    public string IconUrl { get; set; }
    public string Id { get; set; }
    public string Url { get; set; }
    public string Value { get; set; }
}


The above code will only ever get a random joke, so I mapped all the categories in the API to an enum, which I could then use to compare to the message body from Twilio.

public enum JokeCategory
{
    Explicit = 1 << 1,
    Dev = 1 << 2,
    Movie = 1 << 3,
    Food = 1 << 4,
    Celebrity = 1 << 5,
    Science = 1 << 6,
    Sport = 1 << 7,
    Political = 1 << 8,
    Religion = 1 << 9,
    Animal = 1 << 10,
    History = 1 << 11,
    Music = 1 << 12,
    Travel = 1 << 13,
    Career = 1 << 14,
    Money = 1 << 15,
    Fashion = 1 << 16
}
 private (JokeCategory category, bool hasCategory) GetCategory(string message)
{
    var hasCategory = Enum.TryParse(message, true, out JokeCategory cat);
    return (category: cat, hasCategory: hasCategory);
}
public async Task<ChuckNorrisResponse> GetJokeAsync(string message)
{
    var categoryCheck = GetCategory(message);
    var cat = categoryCheck.category.ToString();
    var category = cat != string.Empty ? cat.ToLower() : "";
             
    var response = await GetNewJokeAsync(category).ConfigureAwait(false);

    return response;
}


I have used the new C#7 Value Tuple, explained here in Mark Zhou’s Blog, to return both the bool and the category. I probably didn’t need to do this, as I don’t use the bool for anything (at the moment). However, I fancied using it!

Also, note that the API is case sensitive, so I have used .ToLower() with my category after I have used .ToString().

Now I can update my GetNewJokeAsync method to accept a category (as seen above) and then pick the API endpoint accordingly.

var apiEndpointRandom = "https://api.chucknorris.io/jokes/random";
var apiEndpointCategory = $"https://api.chucknorris.io/jokes/random?category={category}";
var apiEndPoint = category != "0" ? apiEndpointCategory : apiEndpointRandom;
    



image of twilio webhook

We are so close now!!!

Now I just need to set up the initial message to go out to my user. I simply updated the first method I created to the following and extracted it out into a service.

var accountSid = _twilioOptions.AccountSid;
var authToken = _twilioOptions.AuthToken;

TwilioClient.Init(accountSid, authToken);
var phoneNumber = new PhoneNumber(vm.To);
var message = "Want some Chuck Norris?  Please respond with one of the following categories: Random, " + string.Join(", ", Enum.GetNames(typeof(JokeCategory)));

    await MessageResource.CreateAsync(
        to: phoneNumber,
        from: new PhoneNumber(_twilioOptions.PhoneNumber),
        body: message);
    


Also note that I am using appsecrets and appsettings to store my account sid, auth token and my Twilio phone number. I then inject these to the constructor as IOptions. Check out the Joke Service in full.

Now, once the app is running I can send the initial message out to my user.

![image of first text received(/images/posts/twiliochuck/initialText.jpg)

Then I can respond with one of the options:

image of received jok in sms



gif of animated monkey playing drums

I never said any of the jokes were good….. 😉


All of the above code can be found on my github account repository Twilio.Chuck.Norris