Send SMS messages with Crystal and Twilio
Tags: crystal, twilio, sms
Published: 2017-06-26 11:50:36

---
title: Send SMS messages with Crystal and Twilio
published: true
description: Learn how to use Crystal to send SMS messages with the Twilio API
tags: crystal, twilio, sms
cover_image: https://thepracticaldev.s3.amazonaws.com/i/x2obdnhowuib3u3cxc4r.png
canonical_url: https://www.twilio.com/blog/2016/11/send-sms-messages-crystal.html
---

<a href="https://crystal-lang.org/">Crystal</a> is a young programming language with a whole load of potential and it's been a lot of fun playing around with it over the past few weeks. I want to share with you how easy it is to <a href="https://www.twilio.com/docs/api/rest/sending-messages">send SMS messages</a> with Twilio using Crystal.

The Crystal project started in September 2012 and is still going strong. The language hasn't reached version 1 yet, but there are many things about it to get excited about. <a href="https://crystal-lang.org/">The goals of the language are listed front and centre on the Crystal site</a>, but briefly, it is a type-inferred, compiled language with Ruby-like syntax that is blazingly fast. To get started, let's take a look at a simple Crystal program:


```crystal
def fib(n)
  if n <= 1
    1
  else
    fib(n - 1)   fib(n - 2)
  end
end

time = Time.now
puts fib(42)
puts Time.now - time
```

If you've used Ruby before, then this will be instantly recognisable as a function to calculate the nth Fibonacci number. It's so recognisable that if you were to run this with Ruby the program would run correctly. Of course you can run it with Crystal too.

<img alt="Running the program with Ruby produces the answer in 32 seconds, running with Crystal took 1.7 seconds" src="https://twilioinc.wpengine.com/wp-content/uploads/2016/11/SuNpEnzR8dABrzGkPDJ8ovwrd1OJoLg6XlS65qo27hlcCFR1CN89T4Ge6-8TRt3G6hDjvhQGOARjz5G5S-qe1K22vvFagyfIPL6hSzyJhsHFmoCQW-YovaTDlOg9Es2ZJmN38mI.png" class="aligncenter">

Pretty amazing, right? And Crystal is orders of magnitude quicker than Ruby in this test. Of course, the Fibonacci sequence is a terrible benchmark and <a href="https://crystal-lang.org/2016/07/15/fibonacci-benchmark.html">this isn't exactly a fair test either</a>, but it's interesting to see the similarities. As you start to dig into Crystal, however, the differences between this language and Ruby start to emerge.

Let's do that now and make some calls to the Twilio API using Crystal.

## Getting started with Crystal

To use Crystal, you'll first need to install the compiler. For Linux, follow the <a href="https://crystal-lang.org/docs/installation/index.html">installation instructions in the Crystal docs</a>. If you're on a Mac you can install Crystal with <a href="http://brew.sh/">homebrew</a> with the following:

```bash
$ brew update
$ brew install crystal-lang
```

Sadly, Crystal doesn't currently compile on Windows operating systems. 

You can check that Crystal is successfully installed by running:

```bash
$ crystal --version
Crystal 0.19.4 (2016-10-21)
```

We need a Twilio account for the next part, so if you haven't got an account, <a href="https://www.twilio.com/try-twilio">sign up for free here</a>. We will also need a <a href="https://www.twilio.com/console/phone-numbers/incoming">Twilio number</a> that can send SMS messages.

Time to make some API calls with Crystal!

## Sending an SMS message with Crystal

Normally when I write about sending an SMS I would point you towards our <a href="https://www.twilio.com/docs/libraries">official helper libraries</a>. As Crystal is still relatively new, there is no such library, so we're going to have to roll up our sleeves and investigate the HTTP module.

Create a new Crystal file named `sms.cr`:

```bash
$ touch sms.cr
```

Open the file and start by requiring the <a href="https://crystal-lang.org/api/0.19.4/HTTP/Client.html">`http/client` class</a> from the standard library. Start a new function for sending SMS messages using Ruby's familiar `def` syntax. We'll need three arguments; a number to send the message to, the number we're sending from and the body of the message.

```crystal
require "http/client"
def send_sms(to, from, body)

end
```

### Setting up the HTTP Client

Initialise an `HTTP::Client` with the base URL of the API the port number and whether the application uses TLS. We can then pass a block to this initialiser and the client will be closed once we are done with it.

```crystal
require "http/client"
def send_sms(to, from, body)
  HTTP::Client.new("api.twilio.com", 443, true) do |client|

  end
end
```

Now that we have our client, we need to add our authentication header using our Twilio Account SID and Auth Token as the username and password. I'm keeping my credentials as environment variables so that I don't accidentally share them publicly. You can set environment variables on the command line with the `export` command.

```bash
$ export TWILIO_ACCOUNT_SID=AC123456789abcdef
$ export TWILIO_AUTH_TOKEN=1q2w3e4r5t6y7u8i9op0
```

Use the `basic_auth` method on the `HTTP::Client` instance to authenticate the client.

```crystal
require "http/client"
def send_sms(to, from, body)
  HTTP::Client.new("api.twilio.com", 443, true) do |client|
    client.basic_auth(ENV["TWILIO_ACCOUNT_SID"], ENV["TWILIO_AUTH_TOKEN"])
  end
end
```

### Making the HTTP request

Now we can make our request. To <a href="https://www.twilio.com/docs/api/rest/sending-messages">send an SMS message we need to make a POST request to the Messages resource</a>. We build the URL using our Account SID. We need to send the properties of our message as `application/x-www-form-urlencoded` parameters, and we can use Crystal's built in `post_form` method for this:

```crystal
require "http/client"
def send_sms(to, from, body)
  HTTP::Client.new("api.twilio.com", 443, true) do |client|
    client.basic_auth(ENV["TWILIO_ACCOUNT_SID"], ENV["TWILIO_AUTH_TOKEN"])
    response = client.post_form("/2010-04-01/Accounts/#{ENV["TWILIO_ACCOUNT_SID"]}/Messages.json", {
      "To"   => to,
      "From" => from,
      "Body" => body,
    })
  end
end
```

We could now call this function and send our first SMS message from Crystal. But we would only know whether it was a success once we received the message. Let's do a little more work to check whether the API call was successful and if so print out the message SID otherwise print out the error message.

### Handling the response

Include the JSON module from the standard library and parse the response body. If it's a success we can look for the SID otherwise the <a href="https://www.twilio.com/docs/api/rest/response#response-formats-exceptions">error response</a> will have a message field to tell us what went wrong.

```crystal
require "http/client"
require "json"
def send_sms(to, from, body)
  HTTP::Client.new("api.twilio.com", 443, true) do |client|
    client.basic_auth(ENV["TWILIO_ACCOUNT_SID"], ENV["TWILIO_AUTH_TOKEN"])
    response = client.post_form("/2010-04-01/Accounts/#{ENV["TWILIO_ACCOUNT_SID"]}/Messages.json", {
      "To"   => to,
      "From" => from,
      "Body" => body,
    })
    result = JSON.parse(response.body)
    if response.success?
      puts result["sid"]
    else
      puts result["message"]
    end
  end
end
```

Now add one final line to `sms.cr` to call the method with your own phone number in the `to` position, a Twilio number in the `from` position and your SMS message.

```crystal
# sms.cr
def send_sms(to, from, body)
  # function code
end

send_sms(ENV["MY_NUMBER"], ENV["MY_TWILIO_NUMBER"], "Hello from Crystal!")
```

### Compiling and running

Compile and run the function and celebrate your first SMS sent from Crystal!

```bash
$ crystal sms.cr
SMadca071a5bab4848892d9f24863e99e6
```

The crystal command compiles and runs the file you pass to it. You can also build a fully optimised executable that's ready for production with the `build` command.

```bash
$ crystal build sms.cr --release
$ ./sms
SMadca071a5bab4848892d9f24863e99e6
```

We've sent our first message, but there's more to learn before we finish this chapter. JSON parsing using the `JSON.parse` method is fine, but you'll remember that I described Crystal as type-inferred at the start of the post. Parsing arbitrary data structures like JSON in a typed language can be awkward and require you to cast your properties to the expected type before using them. As it happens, the type of each property parsed using `JSON.parse` is <a href="https://crystal-lang.org/api/0.19.4/JSON/Any.html">`JSON::Any`</a> and when we call `puts` with the object it is cast under the hood to a string with `to_s`.

### Improved JSON parsing

Instead of using this `JSON::Any` type, we can actually tell Crystal's JSON parser what to look for with a <a href="https://crystal-lang.org/api/0.19.4/JSON.html#mapping-macro">JSON mapping</a>. This will have the effect of being "easy, type-safe and efficient" according to <a href="https://crystal-lang.org/api/0.19.4/JSON.html">the documentation</a>.

Open up `sms.cr` again and add simple mappings for our message and error objects.

```crystal
# sms.cr
class Message
  JSON.mapping(
    sid: String,
    body: String
  )
end

class Error
  JSON.mapping(
    message: String,
    status: Int32
  )
end
```

There are more fields available on each of those objects, but we are only interested in those for now. Now, instead of using `JSON.parse` we can use the `from_json` constructor for each of our `Message` and `Error` classes. The mapping creates instance variables, getters and setters for the fields we define so we can use dot notation to access them.

```crystal
def send_message(to, from, body)
  client = HTTP::Client.new("api.twilio.com", 443, true) do |client|
    client.basic_auth(ENV["TWILIO_ACCOUNT_SID"], ENV["TWILIO_AUTH_TOKEN"])
    response = client.post_form("/2010-04-01/Accounts/#{ENV["TWILIO_ACCOUNT_SID"]}/Messages.json", {
      "To"   => to,
      "From" => from,
      "Body" => body,
    })
    if response.success?
      message = Message.from_json(response.body)
      puts message.sid, message.body
    else
      error = Error.from_json(response.body)
      puts error.status, error.message
    end
  end
end
```

If you run the file with `crystal sms.cr` again you will receive your message and be safe in the knowledge that your `Message` object is now correctly typed and efficiently parsed from the JSON response.

### Crystal is pretty cool

In my early explorations with Crystal I found it as pleasurable to write as Ruby with the addition of type safety and speed. In this post we've seen how easy it is to use Crystal to make HTTP requests against the Twilio API and <a href="https://www.twilio.com/docs/api/rest/sending-messages#post">send SMS messages</a>. If you want to see the full code, check out this repository on <a href="https://github.com/philnash/crystal-experiments">GitHub</a>. 

If you like the look of Crystal you can learn more about it at the <a href="https://crystal-lang.org/">official site</a> and by checking out the <a href="https://crystal-lang.org/api/0.19.4/">documentation</a>. There are a bunch of interesting projects listed on the <a href="https://github.com/veelenga/awesome-crystal">awesome-crystal</a> repo and if you're coming at this from Ruby, like me, take a read through the <a href="http://www.crystalforrubyists.com/">Crystal for Rubyists book</a>.

What do you think about Crystal? Does it look like a promising language to you? Let me know your thoughts in the comments below or drop me an <a href="mailto:philnash@twilio.com">email</a> or message on <a href="https://twitter.com/philnash">Twitter</a>.

___

_[Send SMS messages with Crystal and Twilio](https://www.twilio.com/blog/2016/11/send-sms-messages-crystal.html) was originally published on the [Twilio blog](https://www.twilio.com/blog) on November 3, 2016._