Crystal — это молодой язык программирования с огромным потенциалом, и за последние несколько недель мне было очень интересно с ним экспериментировать. Я хочу показать вам, насколько просто отправлять SMS-сообщения с помощью Twilio, используя Crystal.
Проект Crystal стартовал в сентябре 2012 года и продолжает активно развиваться. Язык ещё не достиг версии 1.0, но в нём уже есть многое, что вызывает восторг. Цели языка чётко обозначены на сайте Crystal, но вкратце: это компилируемый язык с выводом типов и синтаксисом, похожим на Ruby, который работает невероятно быстро. Давайте начнём с простой программы на Crystal:
Если вы раньше работали с Ruby, то этот код будет вам сразу узнаваем — это функция для вычисления n-го числа Фибоначчи. Он настолько похож, что если запустить его с помощью Ruby, программа выполнится корректно. Конечно, его можно запустить и с помощью Crystal.
Довольно впечатляюще, не правда ли? При этом Crystal в этом тесте работает на порядки быстрее Ruby. Конечно, последовательность Фибоначчи — не самый лучший бенчмарк, и это не совсем честное сравнение, но интересно видеть сходства. Однако по мере погружения в Crystal начинают проявляться различия между этим языком и Ruby.
Давайте сделаем это прямо сейчас и совершим несколько вызовов к Twilio API с помощью Crystal.
Для работы с Crystal сначала нужно установить компилятор. Для Linux следуйте инструкциям по установке в документации Crystal. Если вы используете Mac, можно установить Crystal через Homebrew с помощью следующей команды:
К сожалению, на данный момент Crystal не компилируется в операционных системах Windows.
Убедитесь, что Crystal установлен корректно, выполнив команду:
Для следующего шага нам понадобится аккаунт Twilio, поэтому, если у вас его ещё нет, зарегистрируйтесь бесплатно здесь. Также нам потребуется номер Twilio, с которого можно отправлять SMS-сообщения.
Пришло время сделать несколько API-вызовов с помощью Crystal!
Обычно, когда я пишу о том, как отправить SMS, я рекомендую использовать наши официальные вспомогательные библиотеки. Поскольку Crystal всё ещё относительно новый язык, такой библиотеки нет, поэтому нам придётся засучить рукава и изучить модуль HTTP.
Создайте новый файл Crystal с именем `sms.cr`:
Откройте файл и начните с подключения класса `http/client` из стандартной библиотеки. Создайте новую функцию для отправки SMS-сообщений, используя знакомый синтаксис `def` из Ruby. Нам понадобятся три аргумента: номер получателя, номер отправителя и текст сообщения.
#### Настройка HTTP-клиента
Инициализируйте `HTTP::Client` с базовым URL API, номером порта и указанием, использует ли приложение TLS. Затем можно передать блок в этот инициализатор, и клиент будет закрыт после завершения работы.
Теперь, когда у нас есть клиент, нужно добавить заголовок аутентификации, используя Twilio Account SID и Auth Token в качестве имени пользователя и пароля. Я храню свои учётные данные в переменных окружения, чтобы случайно не раскрыть их публично. Установить переменные окружения можно через командную строку с помощью команды `export`.
Используйте метод `basic_auth` для экземпляра `HTTP::Client`, чтобы аутентифицировать клиент.
#### Выполнение HTTP-запроса
Теперь можно сделать запрос. Для отправки SMS-сообщения нужно выполнить POST-запрос к ресурсу Messages. Мы формируем URL с использованием Account SID. Параметры сообщения нужно отправить в формате `application/x-www-form-urlencoded`, и для этого можно использовать встроенный метод `post_form` в Crystal:
Теперь мы могли бы вызвать эту функцию и отправить первое SMS-сообщение из Crystal. Но мы узнаем об успешности отправки только после получения сообщения. Давайте немного доработаем код, чтобы проверять успешность API-вызова: если он успешен, выведем SID сообщения, в противном случае — сообщение об ошибке.
#### Обработка ответа
Подключите модуль JSON из стандартной библиотеки и распарсите тело ответа. Если запрос успешен, мы можем найти SID, в противном случае в ответе об ошибке будет поле message, которое сообщит, что пошло не так.
Теперь добавьте последнюю строку в `sms.cr`, чтобы вызвать метод с вашим номером телефона в позиции `to`, номером Twilio в позиции `from` и текстом SMS-сообщения.
#### Компиляция и запуск
Скомпилируйте и запустите функцию, и отпразднуйте отправку вашего первого SMS с помощью Crystal!
Команда `crystal` компилирует и запускает переданный ей файл. Также можно создать полностью оптимизированный исполняемый файл, готовый к продакшену, с помощью команды `build`.
Мы отправили первое сообщение, но прежде чем завершить эту главу, нужно узнать ещё кое-что. Парсинг JSON с помощью метода `JSON.parse` подходит, но помните, что в начале статьи я описывал Crystal как язык с выводом типов. Парсинг произвольных структур данных, таких как JSON, в типизированном языке может быть неудобным и требовать приведения свойств к ожидаемому типу перед их использованием. На самом деле, тип каждого свойства, распарсенного с помощью `JSON.parse`, — это `JSON::Any`, и когда мы вызываем `puts` для объекта, он неявно приводится к строке с помощью `to_s`.
#### Улучшенный парсинг JSON
Вместо использования типа `JSON::Any` мы можем указать парсеру JSON Crystal, что именно искать, с помощью JSON-маппинга. Согласно документации, это будет «просто, типобезопасно и эффективно».
Откройте `sms.cr` ещё раз и добавьте простые маппинги для объектов сообщения и ошибки.
У каждого из этих объектов доступно больше полей, но нас интересуют только эти. Теперь вместо `JSON.parse` можно использовать конструктор `from_json` для каждого из наших классов `Message` и `Error`. Маппинг создаёт переменные экземпляра, геттеры и сеттеры для определённых нами полей, так что мы можем использовать точечную нотацию для доступа к ним.
Если вы снова запустите файл с помощью `crystal sms.cr`, то получите своё сообщение и будете уверены, что объект `Message` теперь правильно типизирован и эффективно распарсен из JSON-ответа.
В моих первых экспериментах с Crystal я нашёл его таким же приятным в написании, как и Ruby, но с добавлением типобезопасности и скорости. В этой статье мы увидели, насколько просто использовать Crystal для выполнения HTTP-запросов к Twilio API и отправки SMS-сообщений. Если вы хотите посмотреть полный код, загляните в этот репозиторий на GitHub.
Если вам понравился Crystal, вы можете узнать больше о нём на официальном сайте и изучив документацию. На репозитории awesome-crystal перечислено множество интересных проектов, а если вы, как и я, пришли из мира Ruby, почитайте книгу «Crystal для Ruby-разработчиков».
Что вы думаете о Crystal? Считаете ли вы его перспективным языком? Поделитесь своими мыслями в комментариях ниже или напишите мне на почту или в Twitter.