Building a server-side app - Part 3: Access external APIs

In the previous tutorial, you built a small web app that displayed server-side content in the iframe in Zendesk Support. In this tutorial, you'll update the web app to get data from an external API and display it in the iframe.

The tutorial covers the following tasks:

This tutorial is the third part of a series on building a server-side Zendesk 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 Zendesk Apps framework (ZAF) community, or search for a solution online.

Planning the update

You should have a good idea of how your app will look and work after the update before you start working on it. Let's say you have an Asana project that lists tech notes for your support team to write.

You'd like to display the tech note ideas in the Zendesk Support agent interface. If an agent has time to write a tech note, the agent can click one of them to see the details in Asana.

The updated app looks like this without any formatting niceties:

Note: To build the same app using only client-side technologies, see Getting data from an external application.

Set up an Asana project

The web app will get data from Asana, a popular task management application. If you're not an Asana user, you can sign up for free. This section describes how to set up Asana for the tutorial.

Create an Asana project and add a few tasks

If you already have an Asana account, skip to step 4.

  1. Go to 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.

  4. Create a project by clicking the Plus (+) icon next to the Projects label on the left side and create a new project named "Tech Notes".

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

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

Get a personal access token

You'll need a personal access token from Asana to make API calls from your web 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 "ZAF v2 tutorials" 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.

Show a start page

The web app should display a start page when the app starts in Zendesk Support.

  1. In the app_remote folder, create a new folder named views.

  2. In the views folder, create a template named start.tpl.

  3. Open the start.tpl template in a text editor and add the following HTML:

    <head>  <link href="" rel="stylesheet"></head><body>  <a class="btn btn-default btn-block" href="list" role="button">List tech note ideas</a></body>
  4. In, replace the return statement in the send_iframe_html() function with return template('start'). Example:

    @route('/sidebar')def send_iframe_html():    return template('start')
  5. Because you introduced the Bottle template() method, add template to the list of imported methods on the first line of

    from bottle import route, run, template
  6. In your command-line tool, restart the development server by stopping it with Ctrl+C, then restarting it with $ python3

    You have to restart the server every time you make a change to Python code.

    Note: You don't have to restart it when making cosmetic changes such as CSS or template edits.

  7. Open http://localhost:8080/sidebar in a browser.

    The Boostrap btn-block class stretches the link button across the width of the page. The button adjusts in the sidebar in the agent interface:

    You'll build a route for the link in the next section.

    Tip: Button links gives you flexibility to add more features to your app later. For example, if you want to support creating tasks, you can add a Add tech note idea button to the start page, and then build a route for it:

Show the list page

The web app should display a page to list the tasks when the user clicks the List tech note ideas link on the start page.

  1. In the views folder, create a template named list_tasks.tpl.

  2. Open the list_tasks.tpl template in a text editor and add the following HTML:

    <head><link href="" rel="stylesheet"></head><body>    Task list goes here</body>
  3. In, add the following route after the '/start' route:

    @route('/list')def show_tasks():    # authenticate the request    # make the request    # handle the response    return template('list_tasks')
  4. In your command-line tool, restart the development server by stopping it with Ctrl+C, then restarting it with $ python3

  5. Click the List link on the start page to test that it works.

List the tasks

According to the Asana API docs, the following endpoint returns "the compact task records for all tasks within the given project, ordered by their priority within the project":

GET    /projects/project-id/tasks

The project-id parameter is the id of the project that contains the tasks. Example: 13579.

The doc provides a cURL example:

curl -H "Authorization: Bearer <personal_access_token>" \

This is all the information you need to make an API request.

  1. In the show_tasks() function in, replace the following comment:

    # authenticate the request

    with the following lines:

    access_token = your_access_tokenheader = {'Authorization': 'Bearer {}'.format(access_token)}

    Replace the your_access_token placeholder with your Asana access token.

    This creates an Authorization header for the request. The format() string function interpolates the token value at the curly braces in the string. The result will look as follows:

    header = {'Authorization': 'Bearer 0/861ed62fdd7ad63143c8bb90a90bg6fa'}
  2. Make the request by replacing the following comment:

    # make the request

    with the following lines:

    url = ''r = requests.get(url, headers=header)

    The web app makes a GET request using the requests.get() method from the requests library. You pass the endpoint URL and the authorization header as method arguments.

  3. Replace the your_project_id placeholder in the url string with your project id. You can get the id as follows:

    1. Sign in to Asana, then open a new browser tab.
    2. Paste in the tab's Address bar and press Enter.

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

  4. Handle the response by replacing the following 2 lines:

    # handle the response return template('list_tasks')

    with the following block:

    if r.status_code == 200:   tasks = r.json()   return template('list_tasks', list=tasks['data'])else:    msg = 'Problem with the request: {} {}'.format(r.status_code, r.reason)    return msg

    When you made the request in step 2, you assigned the response to a variable named r. If the request is successful (if r.status_code == 200), the app passes the list of tasks to the template. If the response is not successful, the app displays a plain text error message derived from the response.

    The block uses the requests library's json() method to convert the JSON response to a Python dictionary and assigns it to the tasks variable:

    tasks = r.json()...

    By inspecting the tasks variable, you can learn that it contains a value that looks as follows:

    {'data':  [    {'name': 'Describe printer shutdown workaround', 'id': 145581874072676},    {'name': 'Show the serial number location', 'id': 145581874072678}  ]}

    You're only interested in the list of tasks. You retrieve it with tasks['data'] and pass it to the list_tasks.tpl template:

    ...return template('list_tasks', list=tasks['data'])

    The completed route should look as follows:

    @route('/list')def show_tasks():    access_token = your_access_token    header = {'Authorization': 'Bearer {}'.format(access_token)}    url = ''    r = requests.get(url, headers=header)    if r.status_code == 200:        tasks = r.json()        return template('list_tasks', list=tasks['data'])    else:        msg = 'Problem with the request: {} {}'.format(r.status_code, r.reason)        return msg
  5. Because you introduced the requests library, import it at the top of the file:

<strong>import requests</strong>    from bottle import route, run, template    ...
  1. Switch to the list_tasks.tpl template and replace the following text:

    Task list goes here

    with the following unordered list:

    <ul>  % for task in list:        <li><a href="{{task['id']}}" target="_blank">{{task['name']}}</a></li>  % end</ul>

    The templating code sets up a loop to print the tasks passed to the template in the list parameter. To learn more about the templating language, see SimpleTemplate Engine in the Bottle docs.

  2. Change the project id (155581874072676 in the example) in the href attribute to your project id. See Step 3 above.

To test the updated web app in Zendesk Support:

  1. In your command-line tool, restart the Bottle server by stopping it with Ctrl+C, then restarting it with $ python3

  2. In the Zendesk Support instance running the local ZCLI server, refresh the app and click the first button, List tech note ideas.

    The tasks from Asana should be displayed:

    Clicking a link should bring you to the task in Asana.

In this tutorial, you updated the web app to get tasks from the Asana API and then display them in the Zendesk app. In the next tutorial, you'll learn how to access the Zendesk framework APIs. Get started: Part 4 - Access framework APIs.