PubNub FunctionsUsing external REST APIs

So far we've augmented messages and saved values that were generated locally. In the Age of the Internet, we're going to want to integrate remote data sources via REST calls, and use that information as part of our PubNub Functions logic!

The ability to call into remote APIs is made possible via the XHR module. It's a powerful, easy-to-use PubNub Functions API module that provides all HTTP methods (verbs), with full control over content encoding, headers, and response parsing.

Instead of augmenting our existing Hello World app like we've been doing, let's create a new Function in the same Module called Geocode.

Geocode will use the XHR module to issue a GET request to the Neutrino Geocode service.

To create our new Function:

  1. Click the + symbol next to the Hello World tab to create a new Function.

    Add new EH tab
     

    The Create a Function Handler dialog appears.

    Create New EH Dialog
  2. For Function name, enter Geocode.
  3. For Channel name, enter geocode.
  4. For Select an event, select Before Publish.
  5. Click Create.

    The newly created Logger Function editor comes into focus.

    export default (request) => {
        console.log(request); // Log the request envelope passed
        return request.ok(); // Return a promise when you're done
    };
  6. export default (request) => {
        const xhr = require("xhr");
        const query = require('codec/query_string');
        const query_params = {
    		"user-id": "geremy@pubnub.com",
            "api-key": "HwX6r15P58A9VJCD47vG4cSoCM0OBraiuf6B9jyi2LYUCGi7",
            "address": request.message.address,
    		"country-code": request.message.country
    	};
    
        const url = "https://neutrinoapi.com/geocode-address" + "?" + query.stringify(query_params);
    
        return xhr.fetch(url).then((x) => {
            const body = JSON.parse(x.body);
    		const result = body.locations[0];
    		request.message.country = result.country;
            request.message.zip = result["postal-code"];
    		request.message.address = result.address;
    		request.message.city = result.city;
    		request.message.lat = result.latitude;
    		request.message.lon = result.longitude;
    		return request.ok();
    	});
    };
  7. Click Save.
  8. Click Restart Module.

    Now that we've created our Function code, let's publish a message to it.

  9. {
        "address": "725 folsom street, san francisco, ca", "country": "us"
    }
  10. Click Publish.

    {
        "address": "725 Folsom St, San Francisco, CA 94107, USA",
        "country": "United States",
        "zip": "94107",
        "city": "San Francisco",
        "lat": 37.7833074,
        "lon": -122.3992261
    }

    Feel free to experiment with other input addresses.

 
To pretty print the output JSON (make it easier to read), click anywhere on the JSON output, and it should auto-format!

Before clicking on the JSON, it may look like:

Before

And after clicking on it:

After

So how did we achieve this? Let's pick apart the Function source and dig deeper:

const xhr = require("xhr");

To create the query parameters, we have two options:

  1. We could just hard-code them as a string and then append to the URL.
  2. Or we can store them as attributes in an object, and parse them using the Query module's stringify() method.
const query_params = {
    "user-id": "geremy@pubnub.com",
    "api-key": "HwX6r15P58A9VJCD47vG4cSoCM0OBraiuf6B9jyi2LYUCGi7",
    "address": request.message.address,
    "country-code": request.message.country
};

const url = "https://neutrinoapi.com/geocode-address" + "?" + query.stringify(query_params);
return xhr.fetch(url).then((x) => {...
const body = JSON.parse(x.body);
const result = body.locations[0];

request.message.country = result.country;
request.message.zip = result["postal-code"];
request.message.address = result.address;
request.message.city = result.city;
request.message.lat = result.latitude;
request.message.lon = result.longitude;
return request.ok();

And finally, we return the request promise via the resolvedData var.

It's just that easy to call external web services with PubNub Functions!

It's important to note that in this case, the GET method with query parameters made up the anatomy of our web service request. In some cases, you may want to pass no query parameters, or completely different data, such as special headers, and/or make other HTTP verb-based requests.

In addition to GET requests, we can also make POST, PUT, OPTIONS, DELETE, and PATCH requests; just include a method attribute with the appropriate verb as the value in the httpOptions variable.

export default (request) => {

    const xhr = require("xhr");
    const http_options = {
        "method": "POST", // or PUT
        "body": "foo=bar&baz=faz"
    };

    const url = "http://httpbin.org/post";
    return xhr.fetch(url, http_options).then((x) => {
        const body = JSON.parse(x.body);
        console.log(body);
        return request.ok();
    });

};
export default (request) => {
 
    const xhr = require("xhr");
    const http_options = {
        "method": "POST",
        "headers": {
           "Content-Type": "application/json"
        };
		"body": JSON.stringify({
			"body": "Posting JSON!",
			"to": "Someone Special!"
		})
    };   
 
    const url = "http://httpbin.org/post";
    return xhr.fetch(url, http_options).then((x) => {
        const body = JSON.parse(x.body);
        console.log(body);
        return request.ok();
    });
 
};
export default (request) => {

    const xhr = require("xhr");
    const http_options = {
        "method": "POST",
        "headers": {
            "Content-Type": "application/x-www-form-urlencoded",
        },
        "body": "foo=bar&z=x&abc=123"
    };

    const url = "http://httpbin.org/post";
    return xhr.fetch(url, http_options).then((x) => {
        const body = JSON.parse(x.body);
        console.log(body);
        return request.ok();
    });
};
 
PubNub Functions provides a rich set of tools, and this documentation does not cover all of the potential situations you may encounter. If you need help with a situation not covered by the documentation, please contact PubNub Support.