Integrate GIFs Into a Realtime Chat App with Giphy API and BLOCKS

You can’t hide from them. GIFs are everywhere. Enter Giphy, one of the largest databases and search engines for GIFs. And with it, Giphy offers a variety of APIs for accessing their premier GIF search engine and database. By accessing just one endpoint, Giphy enables a world of creativity and fulfillment in your messaging app.

In this tutorial, we’ll use our new Giphy BLOCK for embedding GIFs into a realtime chat application. With a simple input of /gif ______ in our messaging app, the Giphy BLOCK finds and publishes a GIF related to the search.

Here it is in-action:

A Deeper Look at the Giphy API

Would you want to build your own GIF search engine? We didn’t think so. Giphy provides a ton of advanced functionality. Mapping the latest memes, allowing user upload and GIF creation, cross-language translation and more. Add in the inherent challenges in operating a high-performance content delivery network, and Giphy makes a lot of sense.

Looking closer at the APIs, GIF search is just the beginning. There are a lot of API methods available for things like trending GIFs, translation, stickers, upload, and more. It really is a powerful tool for building in GIF expressions into a wide range of services. In this article though, we’ll keep it simple and implement an easy GIF command that lets a user embed GIFs in their chat messages.

Obtaining Your PubNub Developer Keys

You’ll first need your PubNub publish/subscribe keys. If you haven’t already, sign up for PubNub. Once you’ve done so, go to the PubNub Admin Portal to get your unique keys.

The publish and subscribe keys look like UUIDs and start with “pub-c-” and “sub-c-” prefixes respectively. Keep those handy – you’ll need to plug them in when initializing the PubNub object in your HTML5 app below.

About the PubNub JavaScript SDK

PubNub plays together really well with JavaScript because the PubNub JavaScript SDK is extremely robust and has been battle-tested over the years across a huge number of mobile and backend installations. The SDK is currently on its 4th major release, which features a number of improvements such as isomorphic JavaScript, new network components, unified message/presence/status notifiers, and much more.

NOTE: In this article, we use the PubNub Angular2 SDK, so our UI code can use the PubNub JavaScript v4 API syntax!

The PubNub JavaScript SDK is distributed via Bower or the PubNub CDN (for Web) and NPM (for Node), so it’s easy to integrate with your application using the native mechanism for your platform. In our case, it’s as easy as including the CDN link from a script tag.

That note about API versions bears repeating: the user interfaces in this series of articles use the v4 API (since they use the new Angular2 API, which runs on v4). In the meantime, please stay alert when jumping between different versions of JS code!

Getting Started with the Giphy API

The next thing you’ll need to get started is a Giphy account to take advantage of the GIF search APIs.

Overall, it’s a pretty quick process. And free to get started, which is a bonus!

Setting up the BLOCK

With PubNub BLOCKS, it’s really easy to create code to run in the network. We’ll be pulling in GIFs from Giphy, without worrying about servers at all. All the code and processing runs in the network. That’s the power of BLOCKS. Here’s how to make it happen:

  • Create a new BLOCK.
  • Paste in the BLOCK code from the next section and update the client token with the Giphy API token from the previous steps above.
  • Start the BLOCK, and test it using the “publish message” button and payload on the left-hand side of the screen.

That’s all it takes to create your serverless code running in the cloud!

Diving into the Code – the BLOCK

You’ll want to grab the 41 lines of BLOCK JavaScript and save them to a file called pubnub_gifchat_block.js. It’s available as a Gist on GitHub for your convenience.

First up, we declare our dependency on xhr and query (for HTTP requests) and create a function to handle incoming messages.

export default request => {
    let xhr = require('xhr');
    let query = require('codec/query_string');

Next, we set up variables for accessing the service (the API URL and API key).

    const apiKey = 'YOUR_API_KEY';
    const apiUrl = 'http://api.giphy.com/v1/gifs/search';

Next, we set up a regex for matching our GIF commands, which we want to look like “/gif hello” or “/gif grumpycat”. We use the text attribute of the incoming message as the text string to analyze.

    const regex = /\/gif\s\(([^.?]*)\)|\/gif\s\w+/g;
    let textToAnalyze = request.message.text;

Then, we set up the array of regex matches, and create a rets array to hold the GIF URLs we find.

    const matches = textToAnalyze.match(regex) || [];
    const rets = [];

For each GIF command match, we query the Giphy API and add the corresponding GIF result URL to our list of matches.

    matches.forEach((match) => {
        const queryParams = {
            api_key: apiKey,
            limit: 1,
            rating: 'g',
            q: match.split('/gif')[1]
        };

        let url = apiUrl + '?' + query.stringify(queryParams);

        const a = xhr.fetch(url)
            .then((r) => {
                const body = JSON.parse(r.body || r);
                return body.data[0].images.fixed_height.url;
            })
            .catch((e) => {
                console.error(e);
            });
        
        rets.push(a);
    });

Finally, we resolve all of the GIF query promises, decorate the message with a gifs attribute containing the GIF URLs, and strip the GIF commands from the original text. Pretty easy!

    return Promise.all(rets).then((values) => {
        request.message.gifs = values;
        request.message.text = textToAnalyze.replace(/\/gif\s\(([^.?]*)\)/g, '$1').replace(/\/gif\s/g, '');
        return request.ok();
    });
};

All in all, it doesn’t take a lot of code to add animated GIF embeds to our application. We like that. Let’s move on to the UI!

Diving into the Code – the User Interface

You’ll want to grab these 93 lines of HTML & JavaScript and save them to a file called pubnub_gifchat_ui.html.

The first thing you should do after saving the code is to replace two values in the JavaScript:

  • YOUR_PUB_KEY: with the PubNub publish key mentioned above.
  • YOUR_SUB_KEY: with the PubNub subscribe key mentioned above.

If you don’t, the UI will not be able to communicate with anything and probably clutter your console log with entirely too many errors.

For your convenience, this code is also available as a Gist on GitHub, and a Codepen as well.

Dependencies

First up, we have the JavaScript code & CSS dependencies of our application.

<!DOCTYPE html>
<html>
  <head>
    <title>Angular 2</title>
    <script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script>
    <script src="https://unpkg.com/zone.js@0.7.2/dist/zone.js"></script>
    <script src="https://unpkg.com/reflect-metadata@0.1.9/Reflect.js"></script>
    <script src="https://unpkg.com/rxjs@5.0.1/bundles/Rx.js"></script>

    <script src="https://unpkg.com/@angular/core/bundles/core.umd.js"></script>
    <script src="https://unpkg.com/@angular/common/bundles/common.umd.js"></script>
    <script src="https://unpkg.com/@angular/compiler/bundles/compiler.umd.js"></script>
    <script src="https://unpkg.com/@angular/platform-browser/bundles/platform-browser.umd.js"></script>
    <script src="https://unpkg.com/@angular/forms/bundles/forms.umd.js"></script>
    <script src="https://unpkg.com/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script>

    <script src="https://unpkg.com/pubnub@4.3.3/dist/web/pubnub.js"></script>
    <script src="https://unpkg.com/pubnub-angular2@1.0.0-beta.8/dist/pubnub-angular2.js"></script>

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" />
  </head>

For folks who have done front-end implementation with Angular2 before, these should be the usual suspects:

  • CoreJS ES6 Shim, Zone.JS, Metadata Reflection, and RxJS : Dependencies of Angular2.
  • Angular2 : core, common, compiler, platform-browser, forms, and dynamic platform browser modules.
  • PubNub JavaScript client: to connect to our data stream integration channel.
  • PubNub Angular2 JavaScript client: provides PubNub services in Angular2 quite nicely indeed.

In addition, we bring in the CSS features:

  • Bootstrap: in this app, we use it just for vanilla UI presentation.

Overall, we were pretty pleased that we could build a nifty UI with so few dependencies. And with that… on to the UI!

The User Interface

Here’s what we intend the UI to look like:

The UI is pretty straightforward – everything is inside a main-component tag that is managed by a single component that we’ll set up in the Angular2 code.

<body>
  <main-component>
    Loading...
  </main-component>

Let’s skip forward and show that Angular2 component template. We provide a simple text input for the chat message, as well as a button to perform the publish() action which sends out the data message that will be decorated by the BLOCK.

<div class="container">
    <pre>
    NOTE: make sure to update the PubNub keys below with your keys,
    and ensure that the BLOCK settings are configured properly!
    </pre>
    <h3>MyApp GifChat Integration</h3>
    <div>use a command like "/gif hello" to embed a GIF</div>
    <hr/>
    <input type="text" [(ngModel)]="toSend" />
    <button class="btn btn-primary" (click)="publish()">Send GIF Message!</button>
    <br/>
    <br/>
    <ul class="list-unstyled">
      <li *ngFor="let item of messages.slice().reverse()">
        <div>message: {{item.message.text}}</div>
        <div><img *ngFor="let link of item.message.gifs" [src]="link" /></div>
      </li>
    </ul>
</div>

The component UI consists of a simple list of messages and their corresponding GIFs. We iterate over the messages in the component scope using a trusty ngFor. Each message includes an array of GIFs that we iterate over within a child div.

And that’s it – a functioning realtime UI in just a handful of code (thanks, Angular2)!

The Angular2 Code

Right on! Now we’re ready to dive into the Angular2 code. It’s not a ton of JavaScript, so this should hopefully be pretty straightforward.

The first lines we encounter set up our application (with a necessary dependency on the PubNub AngularJS service) and a single component (which we dub main-component).

<script>
var app = window.app = {};
app.main_component = ng.core.Component({
    selector: 'main-component',
    template: `...see previous...` 

The component has a constructor that takes care of initializing the PubNub service, and configuring the channel name and a blank initial message.

NOTE: make sure the channel matches the channel specified by your BLOCK configuration and the BLOCK itself!

    }).Class({
        constructor: [PubNubAngular, function(pubnubService){
            var self = this;
            self.pubnubService = pubnubService;
            self.channelName = 'pubnub-gif-chat';
            self.toSend = '';

Early on, we initialize the pubnubService with our credentials.

            pubnubService.init({
                publishKey:   'YOUR_PUB_KEY',
                subscribeKey: 'YOUR_SUB_KEY',
                uuid: PubNub.generateUUID(),
                ssl:true
            });

We subscribe to the relevant channel, create a dynamic attribute for the messages collection, and configure a blank event handler since the messages are presented unchanged from the incoming channel.

    pubnubService.subscribe({channels: [self.channelName], triggerEvents: true});
    self.messages = pubnubService.getMessage(this.channelName,function(msg){
      // no handler necessary, dynamic collection of msg objects
    });
}],

We also create a publish() event handler that performs the action of publishing the new text message to the PubNub channel if it’s not empty.

        publish: function(){
            if (this.toSend !== '') {
                this.pubnubService.publish({channel: this.channelName, message:{text:this.toSend}});
                this.toSend = '';
            }
        }
    });

Now that we have a new component, we can create a main module for the Angular2 app that uses it. This is pretty standard boilerplate that configures dependencies on the Browser and Forms modules and the PubNubAngular service.

app.main_module = ng.core.NgModule({
    imports: [ng.platformBrowser.BrowserModule, ng.forms.FormsModule],
    declarations: [app.main_component],
    providers: [PubNubAngular],
    bootstrap: [app.main_component]
}).Class({
    constructor: function(){}
});

Finally, we bind the application bootstrap initialization to the browser DOM content loaded event.

document.addEventListener('DOMContentLoaded', function(){
    ng.platformBrowserDynamic.platformBrowserDynamic().bootstrapModule(app.main_module);
});

We mustn’t forget close out the HTML tags accordingly.

});
</script>
</body>
</html>

Not too shabby for about 93 lines of HTML & JavaScript!

Additional Features

There are a couple other endpoints worth mentioning in the Giphy API.

You can find detailed API documentation here.

  • Search : find GIFs based on words or phrases.
  • Trending : all the most popular trending GIFs.
  • Translate : translate words to GIFs.
  • Stickers : yes, we said stickers!

All in all, we found it pretty easy to get started with GIF embeds using the API, and we look forward to using more of the deeper integration features!

Conclusion

Thank you so much for joining us in the GIF-enabled chat article of our BLOCKS and web services series! Hopefully it’s been a useful experience learning about the latest GIF technologies. In future articles, we’ll dive deeper into additional web service APIs and use cases for other nifty services in realtime web applications.

Stay tuned, and please reach out anytime if you feel especially inspired or need any help!

Try PubNub Today

Connect up to 100 devices for Free