Receive and Respond to Text Messages with Server-Side Swift, Perfect, and Twilio

February 13, 2019
Written by

perfecttwilioswift.jpg

Perfect is a versatile open source server-side Swift framework and toolset that makes it easy for developers to quickly create server- and client-side apps. Let's see how easy it is to send SMS with Twilio and Perfect.

Setup

To follow along with this post we'll need

Install Perfect using the Swift Package Manager. Create a new project directory called PerfectSMS and then on the command line in your project directory, run

swift package init --type executable
swift package generate-xcodeproj

This generates a package with the same name as your current directory.

  1. Package.swift at the top-level of your project contains your package description and your package’s dependencies.
  2. Sources/ is home to all your Swift source files, including main.swift, which will be the entry point for your project. It currently prints hello, world to the Terminal.
  3. Tests/ will contain unit tests you can write using XCTest. We'll be ignoring these for the simplicity of this post.

In Package.swift, add this line to your Dependencies:

"https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.0")

And then this line to your Target Dependencies array:

The complete file should look like this:

import PackageDescription

let package = Package(
    name: "PerfectSMS",
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
        .package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.0")
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "PerfectSMS",
            dependencies: ["PerfectHTTPServer"]),
        .testTarget(
            name: "PerfectSMSTests",
            dependencies: ["PerfectSMS"]),
    ]
)

Setting up your Twilio Account

If you haven't bought a Twilio phone number yet, buy one now. In your current directory, run the command

http 8181

on the command line. If you just installed ngrok and that command gives you an error, you may have to instead run

http 8181

from the directory that the ngrok executable is in.

This gives us a publicly-accessible URL to your application. Configure your Twilio phone number as shown below by adding your ngrok URL with /sms appended to it to the “Messaging” section below:

Send an SMS with Perfect and Twilio

In Sources/PerfectSMS/main.swift, import the following libraries at the top.

import PerfectHTTP
import PerfectHTTPServer
import Foundation

Then create a route to handle different requests based on the HTTP request method and request path. The POST /sms route below will respond to incoming SMS messages. 

 

var routes = Routes()
routes.add(method: .post, uri: "/sms", handler: {
    request, response in
    response.setHeader(.contentType, value: "text/xml")
    let body = request.param(name: "Body", defaultValue: "")
    if let bod = body {
        let respStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><Message><Body>\(bod)</Body></Message></Response>"
        response.appendBody(string: respStr )
            .completed()
    }
})

This code creates a respStr containing TwiML that unwraps the inbound text that is an optional and responds from our Twilio number with the same message that was sent. Now let's launch a HTTP Server, passing it our route we just made.

 

do {
    // Launch the HTTP server.
    try HTTPServer.launch(
        .server(name: "http://1ddc17cd.ngrok.io", port: 8181, routes: routes))
} catch {
    fatalError("\(error)") // fatal error launching one of the servers
}

On the command line in a new tab, run

swift build 
swift run

When your terminal prompts you with a question to "allow incoming connections" click "allow."   Now try sending a text message to your Twilio number and you should get a response back containing the same message you sent.

You can also use Perfect in other environments like Heroku, Amazon Web Services, Docker, Microsoft Azure, Google Cloud, and IBM Bluemix CloudFoundry.

Other neat Twilio and Swift posts include Receiving and Responding to Text Messages with Server Side Swift, Vapor and Twilio, Handling Incoming Phone Calls with Server Side Swift, Vapor and Twilio, and How to receive a POST request with server side Swift using Vapor.

I'd love to hear about what you're building with Twilio in Swift. Feel free to leave a message in the comments below or find me on Twitter @lizziepika, GitHub @elizabethsiegle, or via email lsiegle@twilio.com.