Call Twilio Functions from iOS in Swift

May 09, 2019
Written by

callfuncsfromios.jpg

There are many things you can do from iOS but sometimes, for example, you may need to make a web request to fetch information. With Twilio Functions you can focus on writing the code that matters without having to maintain a server. This tutorial will show you how to set up a Twilio Function that returns a Pokemon joke or two and then call that Function from an iOS application.

excitedpika.gif

Setup

Before you get started, you'll need

  • a Twilio account to create a Twilio Function 
  • Xcode installed to make a rudimentary iOS app to call the Function
  • A little JavaScript (for Twilio Functions) and Swift knowledge

Make a Twilio Function 

The Twilio Function in this tutorial will return a simple hard-coded Pikachu joke. To make that Function, from your Functions page, click the red "+" button to make a new Function.

redplusfunc.png

If this is your first Function, you'll click "Create a Function".

Then select "Blank" to create a Blank Functions Template, and click "Create". You will be redirected directly into your new Function. There on the next page give your Function a name like "Pokemon-Swift-Function" and add on to the path (which is unique to you) something like "/swift".

pokemonswiftfunction.png

Under Access Control, you might have your Function check for a valid Twilio signature before executing which is helpful when creating webhooks for a Twilio application using Functions. However, since we will be calling this Twilio Function directly from a mobile app, the inbound HTTP request will not be signed by Twilio. Make sure to leave this checkbox unchecked, as shown below.

accesscontrolleaveunchecked.png

 

You can also leave "Event" untouched. In the code section add the following JavaScript, which is used in Twilio Functions, to return our basic Pokemon joke:

exports.handler = function(context, event, callback) {
    const joke = 'Why can’t Pokemon play hide-and-seek? Because they\'ll Pikachu!';
    callback(null, joke);
}

Click the red "Save" button at the bottom and your Twilio Function should be deploying! This code will return a single Pokemon joke. The callback is necessary for your Function to finish processing. It has two arguments. The first is an error object: if something went wrong, a description of the error will be returned. However if everything went according to plan, this argument will be null. The second argument is the response which will either be a string, a JavaScript object (which will be converted to JSON), or TwiML (which will be converted to XML.)

You can test that your Function is running by visiting the Function URL path (which you can copy from under Properties above) in a web browser, like below.

copyprops.png

Now let's work on our iOS app that will call the URL and run this JavaScript code.

swiftdance.gif

Call a Twilio Function from iOS

In Xcode, make a new project with the Single View App template and go to main.storyboard. Add a label by clicking the Library button at the top, as shown below.

Then drag a button in the same manner.

In the top right corner, click the button with the two interlocking circles to show the Assistant editor.

Ctrl-drag the button from the Storyboard to the ViewController class to make an Action called buttonClicked. Don't forget to change Connection from Outlet to Action!

Then Ctrl-drag the label from the Storyboard to the ViewController class to make an IB outlet called jokeLabel. No need to change Connection from Outlet this time.

At this point, your ViewController class should look something like this:

In the body of the buttonClicked function, add the following code, replacing "REPLACE-WITH-YOUR-TWILIO-FUNCTION" with your Twilio Function URL.

        let functionURL = "https://REPLACE-WITH-YOUR-TWILIO-FUNCTION.twil.io/swift"
        if let url = URL(string: functionURL) {
            let task = URLSession.shared.dataTask(with: url) {
                data, response, error in
                if error != nil {
                    print(error!)
                } else {
                    do {
                        let responseObject = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [[String: Any]]
                        DispatchQueue.main.async {
                            self.jokeLabel.text = (responseObject![0]["text"] as! String)
                            print(responseObject)
                            self.jokeLabel.font = self.jokeLabel.font.withSize(12)
                        }
                    } catch let error as NSError {
                        print(error)
                    }
                }
            }
            task.resume()
        }

The URLSession class creates a data task that takes as parameters a URL and a closure. Your closure will get the HTTP response, the Data returned by the server, and an error (if there was one) as parameters. We check if the error exists, and if it does not, responseString is created from the Data and is both printed and set as the label text. Finally, resume is called on the task to initiate the HTTP Request - this step is last but not least.

Now run the app and see your Twilio Function called from iOS!

Call a Twilio Function that Returns JSON from iOS

That last Twilio Function returned plain text, but maybe you want to return JSON. Go back to your Twilio Function and replace the code like so:

exports.handler = function(context, event, callback) {
    const whatDoYouCall = { id: 1, text: 'What do you call a storm of Pokemon? A Pokemonsoon!'};
    const pika2 = {
        id: 2,
        text: 'What’s better than one Pikachu? PikaTWO'
    };
    const jokes = [whatDoYouCall, pika2];
    callback(null, jokes);

Then press "Save" and wait for your function to redeploy. Now back in Xcode, remove all the code from the else block and replace it with the following:

let functionURL = "https://REPLACE-WITH-YOUR-TWILIO-FUNCTION.twil.io/swift"
        if let url = URL(string: functionURL) {
            let task = URLSession.shared.dataTask(with: url) {
                data, response, error in
                if error != nil {
                    print(error!)
                } else {
                    do {
                        let responseObject = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [[String: Any]]
                        DispatchQueue.main.async {
                            self.jokeLabel.text = (responseObject![0]["text"] as! String)
                            print(responseObject!)
                        }
                    } catch let error as NSError {
                        print(error)
                    }
                }
            }
            task.resume()
        }

From Xcode, this Twilio Function is called in the same way as our first Twilio Function. However instead of creating a String from data, now we used iOS's built-in JSON Serialization to parse the response data into an array. The full 2D array is printed to the Xcode console and the first joke from the Function is shown on the iOS app's label.

The complete code can be found here on GitHub. Twilio Functions makes it straightforward for developers to focus on their mobile app development by abstracting away some server-side complexities. Let me know in the comments or online how you'll use Twilio Functions from iOS!