Zendesk Apps tutorial - Getting data from an external application

This tutorial shows you how to get data for your apps from external sources.

For the hands-on portion, you'll build a small app that retrieves tasks from Asana, a popular task management application. A free version is available.

The tutorial focuses on getting data. To learn how to send data, see Zendesk Apps tutorial - Sending data to an external application. With a basic knowledge of two-way interactions, you can integrate many web services in your organization's support workflow.

The tutorial assumes you have latest version of the Zendesk Apps Tools (ZAT), a collection of development tools for building apps rapidly. See Installing and using the Zendesk Apps Tools.

The tutorial shows you how to build a client-side app, meaning all the code runs on the client -- the agent's browser. You can also build a server-side version of this app. For a step-by-step guide, see Building a server-side app.

Disclaimer: Zendesk provides this article for instructional purposes only. The Zendesk Support team does not provide support for the content. Please post any issue in the comments section below or in the Zendesk Apps community, or search for a solution online for issues with third-party technologies like Handlebars.

Core concepts

Zendesk apps get external data by making HTTP requests. If the app makes requests to a public API that doesn't require authentication or any other sensitive information, then you can use jQuery.ajax() or the standard XMLHttpRequest JavaScript API.

However, when making AJAX requests from an app installed in a Zendesk product like Zendesk Support, the request settings can be viewed in the browser console by agents. Some settings may contain sensitive information such as an API key or token. Example:

You can hide the information from agents by using the framework's client.request() method and storing the information in Zendesk Support with an app installation setting. Zendesk Support then inserts the information in the request server-side in the proxy layer, bypassing the browser.

Creating a secure request is a four-step process. First, you configure the request. Second, you secure any sensitive settings. Third, you send the request. Fourth, you wait for the request's outcome and handle its success or failure.

  1. Configure the request
  2. Secure sensitive information
  3. Make the request
  4. Handle the outcome of the request

Step 1: Configure the request

You specify the settings of a request in a JavaScript object. Example:

var settings = {  url: 'https://example.com/api/v1/teams',  headers: {"Authorization": "Bearer PyOAYC3N62gqpf"},  type: 'GET',  dataType: 'json'};...

The settings object in the example has 4 properties necessary to complete this particular request:

  • url specifies the URL of the resource
  • headers specifies HTTP headers, in this case an authorization header to authenticate the request. You can secure the information in the headers before deploying the app, as explained in the step 2
  • type specifies the type of request to make, such as GET or POST
  • dataType specifies the type of data you expect back from the server

The settings may vary depending on the request. They include many of the same options as jQuery.ajax() requests. For details, see the jQuery documentation.

Step 2: Secure sensitive information

You should secure any sensitive information in your request settings before deploying the app.

You can store the information in Zendesk Support and Zendesk Support will insert it in your requests on the server side, bypassing the browser on the client side.

You store settings in Zendesk Support by specifying them as installation settings. Not to be confused with request settings, these are the settings a Zendesk Support admin is prompted to enter when installing the app.

You don't need to perform this task until you're ready to deploy the app for the first time. You can build and test your app locally with sensitive information in your code because you're the only one making the requests. Securing the information should be the last step before uploading the app for others to use for the first time.

To secure sensitive information

  1. Create an installation setting in the manifest.json file as follows:

    ..."parameters": [  {    "name": "token",    "type": "text",    "secure": true,    "required": true  }],...

    This adds a required field labeled token on the app's installation page in Zendesk Support. The admin must enter a token before the app can be installed.

  2. Allow the resource's domain name by specifying a "domainWhitelist" property:

    "domainWhitelist": ["example.com"],...

    Specify only the domain name or names in the array. Don't include "https://".

  3. In your request settings, replace the sensitive information with a {{setting.name}} placeholder, and add a secure: true property. Example:

    var settings = {  url: 'https://www.example.com/api/v1/teams',  headers: {"Authorization": "Bearer {{setting.token}}"},  secure: true,  type: 'GET',  dateType: 'json'};

At this point you'd normally upload and install the app in Zendesk Support. You'll be prompted to enter the secure information during the installation process. Example:

After installing the app, you can still make and test changes in the app installed in Zendesk Support. See Updating an installed app in the developer docs.

Step 3: Make the request

You make requests using the request() method of the ZAFClient object. The client provides an interface between your iframe app and a host application such as Zendesk Support.

Use the ZAFClient.init() method to create the client, then call the request() method with your request settings:

var client = ZAFClient.init();client.request(settings).then(...);

Step 4: Handle the outcome of the request

Check for confirmation from the server that the request was successful. A request can fail for a number of reasons, including a network problem or a problem in your code.

You handle the outcomes with callback functions. Callbacks are executed only when a request is finished. For example, you can tell your app to run one function if the completed request was successful, and run another function if the request was not.

You specify the callbacks as arguments of the then() method of the Promise returned by the request. The then() method is called only when the request is finished.

The method takes two arguments: a function to run on success and a function to run on failure. Example:

client.request(settings).then(  function(data) {    showInfo(data);  },  function(response) {    showError(response);  });

If the request succeeds, the response body is passed to the showInfo() function, which is then executed.

Try it: Build an app that gets external data

In this section you'll build a small app that creates tasks in Asana, a popular task management application. Asana has the advantage of being easy to set up and use. If you're not an Asana user, you can sign up for the free version.

Let's say you have an Asana project that lists tech notes that your support team needs to write. You decide to build an app to display the list in the Zendesk Support agent interface. If an agent has time to write a tech note, the agent can click one of them to go to Asana to learn more about the task.

The completed app looks like this without any formatting niceties:

Steps for building this app:

  1. Create a free Asana account
  2. Create a project and add a few tasks
  3. Get a personal access token
  4. Create the files for the app
  5. Adapt the files to your project
  6. Show a start screen
  7. Get the task data
  8. Display the task data
  9. Handle request errors
  10. Refactor the template code
  11. Test and update the app locally
  12. Secure sensitive information
  13. Upload and install the app
  14. Test and update the app after installing it

Before you start, make sure you have the latest version of the Zendesk Apps Tools (ZAT). See Installing and using the Zendesk Apps Tools.

Create a free Asana account

If you don't already have an Asana account, you can sign up for free.

  1. Go to https://asana.com/ and sign up using Google, or enter your email address and click Get Started for Free.

  2. If not using Google, complete your profile by entering your name and a password.

  3. Enter team members if you like (optional), then enter "Support Team" as your team name. You can share tasks with members of the team.

You're done. For Asana basics, see the Fundamentals guide on the Asana site.

Create a project and add a few tasks

  1. After signing in to Asana, click the Plus (+) icon next to the Projects label on the left side and create a new project named "Tech Notes".

  2. On the Tech Notes project page, click Add Task and enter a task to write a tech note on some subject. Example: "Clarify the serial number location".

  3. Add one or two more tech notes that need to be written.

Get a personal access token

You'll need a personal access token from Asana to make API calls from your app.

  1. After signing in to Asana, click your user icon on the top-right side and select My Profile Settings.

  2. In the My Profile Settings dialog box, click Manage Developer Apps.

  3. Under the Personal Access Tokens heading, click the Create New Personal Access Token link.

  4. Enter a brief description for the token such as "Apps v2 data tutorial" and click Create.

  5. Save the token someplace safe. It won't be displayed again.

    If you lose it, return to this page to deauthorize it and create a new one.

Create the files for the app

Use the Zendesk Apps Tools to create a basic set of files for the app.

  1. If not already done, create a folder called "tutorial_apps" somewhere on your hard drive.

  2. Open your command-line interface (the command prompt in Windows or Terminal on the Mac) and navigate to the "tutorial_apps" folder.

  3. Run the following command at the prompt:

    $ zat new
  4. When prompted, enter the following information:

    • author's name - your name
    • author's email - your email
    • author's url - your website url if you have one, or press Enter to leave it blank
    • app name - Data Access Tutorial v2
    • iFrame URI - press Enter to leave it blank. You'll use the default iframe file created by ZAT
    • directory name - data_access_v2

After you're done, the tool creates files for a new app. The window should look as follows in Mac OS X:

The tool also records properties about the app in the manifest.json file, including the host application (Zendesk Support), the app's location in the host (ticket sidebar), and the path to the file to be iframed in the host (assets/iframe.html). Example:

"location": {   "support": {     "ticket_sidebar": "assets/iframe.html"   }},...

Adapt the files to your project

The Apps framework gives you a lot of freedom. You decide how to structure the files, what technologies to use, and more. For the tutorial, you'll make the following changes to the default files to adapt them to your project:

  • Import the third-party libraries you'll need
  • Add a content placeholder in the HTML for your templates
  • Keep your JavaScript separate from your HTML

Tip: You can save and reuse these files in other projects, or create your own set of reusable files.

Import libraries

A Zendesk app consists of dynamic content displayed in an iframe in the host application. You can write everything from scratch yourself but it's much easier to use existing libraries.

In this tutorial, you'll use a bit of jQuery in your JavaScript, Handlebars as your templating engine, and Bootstrap CSS for styling.

  1. In a text editor, open the assets/iframe.html file.

  2. Link to the Bootstrap CSS by replacing the Zendesk Garden CSS in the <head> tag with the following link tag:

    <head><link href="https://cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"></head>...
  3. Import the jQuery and Handlebars libraries by adding the following <script> tags after the <h2> tag in the body:

    ...<script src="https://cdn.jsdelivr.net/jquery/3.0.0/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>

    You can import the libraries from whatever source you like.

Add a content placeholder

In Handlebars, you insert the HTML generated by a template at runtime into an element in the DOM. You decide to use a div tag in the body to insert your template content.

  • Replace the <h2> heading, "Zendesk Apps Tools Iframe Scaffold", which you don't need, with the following div tag:

    <div id="content"></div>
Keep your JavaScript separate

It's best practice to keep your JavaScript separate from your HTML.

  1. Replace the following <script> tag:

    <script>// Initialise the Zendesk JavaScript API client// https://developer.zendesk.com/apps/docs/agent/zaf_v2var client = ZAFClient.init();client.invoke('resize', { width: '100%', height: '400px' });</script>

    with the following tag:

    <script type="text/javascript" src="main.js"></script>

    You'll move the JavaScript to the new main.js file below.

    Make sure the tag is after all the other script tags to ensure the imported libraries are loaded in memory before the browser reaches your script.

  2. Create a file named main.js file in the assets folder.

  3. In main.js, add the following function, which contains the JavaScript code you deleted from iframe.html above:

    $(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });});

    This jQuery statement defines a self-invoking, anonymous function that runs after iframe.html has finished loading in the browser.

  4. Save both files.

The iframe.html file should look like this:

<html><head>  <link href="https://cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"></head><body>  <div id="content"></div>
  <script src="https://cdn.jsdelivr.net/jquery/3.0.0/jquery.min.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>  <script type="text/javascript" src="https://assets.zendesk.com/apps/sdk/2.0/zaf_sdk.js"></script>  <script type="text/javascript" src="main.js"></script></body></html>

The main.js file should look like this:

$(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });});

Show a start screen

You want to show something to users when the app starts. To keep it simple, you'll display a link to get the tasks.

In Handlebars, you create templates by including the markup in <script> tags in the main HTML file.

Note: You can also precompile templates, but that's beyond the scope of this tutorial. For more information, see How to Precompile Handlebars Templates.

  1. In your iframe.html file, add the following <script> tag before all the other <script> tags:

    <script id="start-hdbs" type="text/x-handlebars-template">  <p><a id="get-tasks" href="#">Get tasks</a></p></script>

    The template consists of a simple "Get tasks" link.

  2. Switch to main.js and add the following showStart() function definition to the file:

    function showStart() {  var source = $("#start-hdbs").html();  var template = Handlebars.compile(source);  var html = template();  $("#content").html(html);}

    This function generates and inserts the HTML from the start-hdbs template into your iframe.html file at runtime. The first line references the <script> tag with an id of start-hdbs, which contains the template. The second line compiles the template. The third line generates the final HTML. The final line sets the HTML content of the <div> tag with an id of content.

  3. Add a call to the showStart() function in the self-invoking function at the top of the file:

    $(function() {  ...  showStart();});

    When the HTML file has finished loading in the browser, the anonymous function runs the showStart() function, which displays the content in the user interface.

  4. Save both files.

At this point, your main.js file should look like this:

$(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });  showStart();});
function showStart() {  var source = $("#start-hdbs").html();  var template = Handlebars.compile(source);  var html = template();  $("#content").html(html);}

Get the task data

You want to make a request when the user clicks the "Get tasks" link. To do so, you'll create a listener for the click event, and a function to make the request when the event is detected.

  1. Add the following jQuery event listener to the anonymous function, after the showStart() call:

    ...$("#get-tasks").click(function() {  getTaskData(client);});

    The event listener runs the getTaskData(client) function when a click on the element with an id of "get-tasks" is detected. You pass the client variable to the function because it needs it to make the HTTP request. You'll define the function next.

    Note: The event listener is defined inside the anonymous function rather than outside of it because the "get_tasks" link doesn't exist in the DOM until the link is inserted by showStart().

  2. Add the following function definition to main.js:

    function getTaskData(client) {  var settings = {    url: 'https://app.asana.com/api/1.0/projects/your_project_id/tasks',    headers: {"Authorization": "Bearer your_personal_access_token"},    type: 'GET',    dataType: 'json'  };  // make request}

    The settings object contains all the properties necessary to complete the API request based on the Asana's Get Project Tasks doc.

  3. Replace the your_personal_access_token placeholder in the request settings with the personal access token you created earlier. See Get a personal access token above.

  4. Replace the your_project_id with the id of your Tech Notes project in Asana, which you can get as follows:

    1. Sign in to Asana, then open a new browser tab.

    2. Paste https://app.asana.com/api/1.0/projects/ in the tab's Address bar and press Enter.

      Your projects and their ids should appear in the browser window.

  5. Replace the // make request comment with the following client.request() method call:

    client.request(settings).then(  function(data) {    console.log(data);  },  function(response) {    console.log(response);  });

    If the request is successful, the first callback function is executed. If not, the second one is executed. You'll add actions to these callbacks in the next section.

  6. Save the file.

At this point, the main.js file should look like this:

$(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });  showStart();
  $("#get-tasks").click(function() {    getTaskData(client);  });
});
function showStart() {  var source = $("#start-hdbs").html();  var template = Handlebars.compile(source);  var html = template();  $("#content").html(html);}
function getTaskData(client) {  var settings = {    url: 'https://app.asana.com/api/1.0/projects/152581874072276/tasks',    headers: {"Authorization": "Bearer 0/266ed62fce7ab63043c8ba20a90be6da"},    type: 'GET',    dataType: 'json'  };  client.request(settings).then(    function(data) {      console.log(data);    },    function(response) {      console.log(response);    }  );}

Display the task data

You need to know the structure of the JSON response from the API to know how to access and display the data in a template. You can find the information in the Get Project Tasks doc on the Asana Developers website.

The docs give the following JSON response example:

HTTP/1.1 200{  "data": [    {      "id": 2001,      "name": "Catnip"    },    {      "id": 2002,      "name": "Kitty litter"    },    ...  ]}

The JSON consists of an array named data, which contains a list of tasks.

To display the task data in a template

  1. In the getTaskData()function in main.js, replace the console.dir(data) statement in the success callback with a call to a new function called showTaskData():

    client.request(settings).then(function(data) {  showTaskData(data);},...);

    You'll define the function next. For now, you pass the response data in an argument named data.

  2. Add the following showTaskData() function definition to main.js:

    function showTaskData(tasks) {  var context = {    project_tasks: tasks.data  };  var source = $("#tasks-hdbs").html();  var template = Handlebars.compile(source);  var html = template(context);  $("#content").html(html);}

    The function accepts the tasks information you passed to it. Using your knowledge of the way the response data is structured (see above), you assign the array of tasks to the project_tasks property of the JavaScript object that'll serve as the template's context. The function then compiles the template, generates the HTML, and uses it to set the HTML content of the content div tag in the iframe.html file.

  3. Switch to your iframe.html file and add the template for the task data:

    <script id="tasks-hdbs" type="text/x-handlebars-template">    <p>Tech notes tasks:</p>    <ul>    {{#each project_tasks}}    <li><a href="https://app.asana.com/0/155581874072676/{{id}}" target="_blank">{{name}}</a></li>    {{/each}}    </ul></script>

    The template contains an {{#each}} block to iterate through the array of tasks supplied by the context object, project_tasks. The {{id}} expression is replaced in each iteration by the item's task ID.

  4. Change the project id (155581874072676 in the example) in the link to your project id. You can get the id from the url in your request settings in main.js.

  5. Save the files.

Handle request errors

Next, you need to display a template when a request is not successful.

  1. In the getProjectTasks()function in main.js, replace the console.log(response) statement in the failure callback with a call to a new function called showError():

    client.request(settings).then(  ...  function(response) {    showError(response);  },);

    You'll define the function next. For now, you pass the HTTP response as an argument named response.

  2. Add the following showError() function definition to main.js:

    function showError(response) {  var context = {    'status': response.status,    'statusText': response.statusText  };  var source = $("#error-hdbs").html();  var template = Handlebars.compile(source);  var html = template(context);  $("#content").html(html);}

    You assign response values to the properties of the template's context object. The function then compiles the template, generates the HTML, and uses it to set the HTML content of the content div tag in the iframe.html file.

  3. Switch to your iframe.html file and add the template for the error message:

    <script id="error-hdbs" type="text/x-handlebars-template">  <p>Problem with the request: {{status}} {{statusText}}</p></script>
  4. Save both files.

Refactor the template code

In main.js, the following 4 lines of nearly identical template code are repeated in 3 places -- showStart(), showTaskData(), and showError():

var source = $("#element_id").html();var template = Handlebars.compile(source);var html = template(context);$("#content").html(html);

The situation cries out for refactoring. You decide to replace the 4 lines with a call to a new helper function called switchTo(). Example call:

switchTo('template-name-hdbs', context);
  1. Add the following helper function to main.js:

    function switchTo(template_name, context) {  var template_id = "#" + template_name;  var source = $(template_id).html();  var template = Handlebars.compile(source);  if (context) {    var html = template(context);  } else {    var html = template();  }  $("#content").html(html);}

    Some templates such as the splash template don't have a context, so the switchTo() function includes an if clause to handle the case.

  2. In showStart(), replace the following four lines:

    var source = $("#start-hdbs").html();var template = Handlebars.compile(source);var html = template(context);$("#content").html(html);

    with:

    switchTo('start-hdbs');
  3. In showTaskData(), replace the four lines with:

    switchTo('tasks-hdbs', context);
  4. In showError(), replace the four lines with:

    switchTo('error-hdbs', context);
  5. Save the file.

Test and update the app locally

  1. In the command-line interface, navigate to your data_access_v2 folder.

  2. Start the local HTTP server with the following command at the prompt:

    $ zat server

    Note: If you get an error, make sure you navigate to your app's folder using the command line.

    After a moment, a status message appears informing you that the server has started.

    Note: The command prompt is unavailable until you shut down the server later.

  3. In a web browser, navigate to any ticket in Zendesk Support. The URL should look something like this:

    https://subdomain.zendesk.com/agent/tickets/321

  4. Append ?zat=true to the ticket URL, and reload the page.

    The URL should look like this:

    https://subdomain.zendesk.com/agent/tickets/321?zat=true

  5. In your browser's Address bar, click the shield icon on the left (Chrome) or lock icon on the right (Firefox) and agree to load an unsafe script (Chrome) or to disable protection (Firefox). If you don't do this, the browser will block your app.

    Note: Safari has no option to disable protection. You must use Chrome or Firefox.

    The browser should reload the page and display the app start page (such as it is) in the ticket sidebar.

  6. Click the Get tasks link.

    The app should display the tasks contained in the Tech Notes project in Asana:

  7. If you like, continue enhancing the app and testing the changes.

    When you're done, switch back to your command-line interface and press Control+C to shut down the local server.

Secure sensitive information

Before uploading and installing the app in Zendesk Support, make sure to secure any sensitive information that you don't want agents to see in the browser console. In this case, you don't want your authentication information to be visible.

Note: After securing the information, you'll no longer be able to test the app locally with the ZAT server. However, you'll still be able to test and update the app after installing it. We'll cover how in Test and update the app after installing it below.

  1. In the manifest.json file, add a parameters property to create an installation setting, as follows:

    ..."parameters": [  {    "name": "token",    "type": "text",    "secure": true,    "required": true  }],...

    The admin will have to enter a value for token before the app can be installed.

  2. Add a "domainWhitelist" property to allow the resource's domain name:

    "domainWhitelist": ["app.asana.com"],...

    Specify only the domain name. Don't include "https://".

  3. In your request settings in main.js, replace the actual token with the {{setting.token}} placeholder, then add a secure: true property. Example:

    var settings = {  url: 'https://app.asana.com/api/1.0/projects/155581874072676/tasks',  headers: {"Authorization": "Bearer {{setting.token}}"},  secure: true,  type: 'GET',  dateType: 'json'};
  4. Save the files.

The completed main.js file should look as follows:

The completed manifest.json file should look as follows:

{  "name": "Data Access Tutorial v2",  "author": {    "name": "Charles Nadeau",    "email": "[email protected]",    "url": ""  },  "defaultLocale": "en",  "private": true,  "location": { "zendesk":    { "ticket_sidebar": "assets/iframe.html" }  },  "domainWhitelist": ["app.asana.com"],  "parameters": [     {       "name": "token",       "type": "text",       "secure": true,       "required": true     }   ],  "version": "1.0",  "frameworkVersion": "2.0"}

Upload and install the app

  1. Validate your files:

    $ zat validate

    Fix any problems reported by the tool, then run zat validate again.

  2. Package your files for upload:

    $ zat package
  3. Upload and install the app as a private app in your Zendesk Support instance. For instructions, see Uploading and installing your private app in Zendesk Support.

  4. During the install process, paste your Asana personal access token in the token field:

After you're done, you can view and test the app in the agent interface. If you need to debug or make additional changes, you can make updates to the installed app as described in the next section.

Test and update the app after installing it

After securing your sensitive information, you can no longer test the app locally with the ZAT server. However, you can still test and update the app after installing it as described in this section.

  1. Make sure you're signed in to Zendesk Support, then paste the following URL in the browser's Address bar, replace your_subdomain in the URL with your own, and press Enter:

    https://your_subdomain.zendesk.com/api/v2/apps/installations.json

    You should see a JSON object listing all the apps installed in your instance of Zendesk Support.

  2. Find your app and copy the app_id.

  3. Create a file named .zat in the local root directory of your app.

    Creating files with a leading period can be problematic in both Mac OSX and Windows.

    On a Mac, you can run the following command in the app's root directory:

    $ touch .zat

    In Windows, create the file in NotePad with File > Save As.

  4. Add the following JSON object to the file:

    {  "subdomain": "your_subdomain",  "username": "your_username",  "app_id": 0000}

    Replace the property values with your own values. The username is your Zendesk Support account username, which is always an email address.

  5. Make changes to your app.

  6. Update the installed app with your changes by running the following command and entering your Zendesk Support account password.

    $ zat update
  7. In Zendesk Support, refresh the apps and test your app.

  8. If you like, continue enhancing the app and testing the changes. Some ideas:

    • Apply some CSS to make it look more professional. Remember that you have all of the Bootstrap CSS at your disposal, which you can customize with your own rules
    • Spruce up the splash page by adding your own logo. See Changing the logo in the getting started tutorial

Additional resources