Search code examples
javahttptwiliotwilio-twimlspark-framework

Passing phone input via Twilio


I'm working on a basic Twilio web application using Java and the Spark Java framework. I'm trying to have the user enter a number as input after the initial prompt through a Gather verb and then process that input. So far, I am able to call my Twilio number and it responds with the initial prompt, but after I enter a number it goes to /handle-number and crashes because the request did not contain any params and it can't find the "Digits" param (params is empty when I print it).

I have tried to mimic the API call via the Postman Chrome extension to debug it, but I get a 500 internal server error.

EDIT: Here is a screenshot of the postman request : Postman screenshot

I am new to Java web applications, HTTP requests, and Twilio, so I am unfamiliar with much of this. I have gone thought the twiml documentation and tutorials and tried to follow along but my I'm definitely missing something in my implementation.

How do I properly pass the phone input to the processNumber Route? Any help is appreciated!

App.java

import static spark.Spark.*;

public class App {
    public static void main (String[] args){
        post("/receive-call", ReceiveCall.call);
        post("/handle-number", ReceiveCall.processNumber);
    }
}

ReceiveCall.java

import com.twilio.twiml.voice.Gather;
import com.twilio.twiml.voice.Say;
import com.twilio.twiml.*;
import spark.Route;

public class ReceiveCall {

    public static Route call = (request, response) -> {    
        Say sayMessage = new Say.Builder("Hello! Please enter a number as input. Enter # when finished.").build();
        Gather input = new Gather.Builder().timeout(3).say(sayMessage).action("/handle-number").build();
        VoiceResponse twiml = new VoiceResponse.Builder().gather(input).build();

        System.out.println(response.body());

        return twiml.toXml();
        };

    public static Route processNumber = ((request, response) -> {    
        String digit = request.params("Digits");

        //CRASHES HERE BECAUSE digit IS NULL
        int number = Integer.parseInt(digit);

        Say message = process(number);
        VoiceResponse twiml = new VoiceResponse.Builder().say(message).build();
        return twiml.toXml();
    });

Solution

  • The reason of "digit IS NULL" is: you are using request.params(...), which is for path parameter.

    What is "path parameter"?

    "path parameter" means passing parameter as part of URL path, especially in RESTful style request.

    For example, if you want to send an HTTP GET request to retrieve a book by its ISBN, the request URL could be: /books/9787121022982 or /books/9787101054491, where the ISBN parameter is passed as part of URL path (9787121022982 and 9787101054491). In Spark framework, the corresponding Route code would be:

    get("/books/:isbn", (request, response) -> {
        return "Book ISBN is: " + request.params(":isbn");
    });
    

    What is "query parameter"?

    "query parameter" means passing parameter as part of URL queries (entities after the ? character in URL).

    Take the previous book ISBN case for example, if you want to pass ISBN as query parameter, the HTTP GET URL would be: /books?isbn=9787121022982, and the corresponding Spark Route code is:

    get("/books", (request, response) -> {
        return "Book ISBN is: " + request.queryParams("isbn");
    });
    

    What is the best practice to pass data in POST request?

    In your case, the /handle-number route accept POST request. For HTTP POST request, it's not a good practice to pass data as parameter in URL. Instead, you need to pass data as request body, and get data from body in Spark code:

    post("/handle-number", (request, response) -> {
        String body = request.body();
        // extract ISBN from request body string
    });