• Stars
    star
    249
  • Rank 162,987 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 10 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Official node.js and browser JS client for the Asana API v1

Asana GitHub release Build Status NPM Version

A JavaScript client (for both Node and browser) for the Asana API v1.0.


Try a preview of our new node client library: node-asana-preview


Installation

Node

Install with npm:

npm install asana --save

Browser

Include the latest release directly from GitHub.

<script src="https://github.com/Asana/node-asana/releases/download/<LATEST_RELEASE>/asana-min.js"></script>

OR:

  1. Download the latest distribution in releases.
  2. Make sure to serve it from your webserver.
  3. Include it on the client from a <script> tag.

Design Decisions

  • Thin Wrapper This client is a thin wrapper, which means that the client makes little attempt to verify the validity of the arguments locally. All errors are reported by the server. We include custom Error types which contain the response from the server.
  • Promises Promises with bluebird seem like the most neutral way to support node's various async paradigms. If you want Promises, you get them by default. If you want callbacks, bluebird promises support nodeify, which takes a callback as parameter. For generators and streams, co and highland also support promises, respectively. Beyond that, other major libraries such as mongoose, mocha, and elastic search (which uses bluebird) also support Promises.

Usage

To do anything, you'll need always an instance of an Asana.Client configured with your preferred authentication method (see the Authentication section below for more complex scenarios) and other options.

The most minimal example would be as follows:

const asana = require('asana');
const client = asana.Client.create().useAccessToken('my_access_token');
client.users.me().then(function(me) {
  console.log(me);
});

All resources are exposed as properties of the Asana.Client instance (e.g. client.workspaces). See the [developer documentation][api-reference] for docs on each of them.

Authentication

This module supports authenticating against the Asana API with either a Personal Access Token or through OAuth 2.0.

Personal Access Token

const client = Asana.Client.create().useAccessToken('personal_access_token');

OAuth 2.0

Authenticating through OAuth2 is preferred. There are many ways you can do this.

In all cases, you should create a Client that contains your app information. The values in the below snippet should be substituted with the real properties from your application's settings.

const client = Asana.Client.create({
  clientId: 123,
  clientSecret: 'my_client_secret',
  redirectUri: 'my_redirect_uri'
});
With a plain bearer token (doesn't support auto-refresh)

If you have a plain bearer token obtained somewhere else and you don't mind not having your token auto-refresh, you can authenticate with it as follows:

client.useOauth({
  credentials: 'my_access_token'
});
With a refresh token

If you obtained a refresh token (from a previous authorization), you can use it together with your client credentials to authenticate:

const credentials = {
  // access_token: 'my_access_token',
  refresh_token: 'my_refresh_token'
};
client.useOauth({
  credentials: credentials
});

See examples/oauth/webserver for a working example of this.

Client OAuth

Currently, Asana has removed support for implicit grant and client-side authorization code grant. To correctly implement oauth in a browser, use your own server as the token exchange endpoint:

Asana.Client.create({
    clientId: clientId,
    redirectUri: 'http://localhost:' + port + '/oauth_callback',
    tokenExchangeEndpoint: 'https://my-app-server.io/oauth_token'
  });

When a request comes to your server, verify it's a valid request (either using your own login cookie, cors, etc.). Then take the body, add your client_secret to it, and send a POST request with the body to https://app.asana.com/-/oauth_token. This will give your server the access and refresh tokens. Either return the access_token to the browser, or keep it on your server if your server handles requests to Asana.

Here is an express example for AWS Lambda that works as an app server.

Your client side code will look similar to the webserver example, but with client side routing instead of express.

Collections

Whenever you ask for a collection of resources, you will receive a Collection object which gives you access to a page of results at a time. You can provide a number of results per page to fetch, between 1 and 100.

It defaults to 50 if you don't provide any.

client.tasks.getTasksForTag(tagId, { limit: 5 }).then(function(collection) {
  console.log(collection.data);
  // [ .. array of up to 5 task objects .. ]
});

Additionally, Collection has a few useful methods that can make them more convenient to deal with.

Individual page iteration

To get the next page of a collection, you do not have to manually construct the next request. The nextPage() method takes care of this for you:

client.tasks.getTasksForTag(tagId).then(firstPage => {
  console.log(firstPage.data);
  firstPage.nextPage().then(secondPage => {
    console.log(secondPage.data);
  });
});

Automatic page iteration

To automatically fetch a bunch of results and have the client transparently request pages under the hood, use the fetch() method:

client.tasks.getTasksForTag(tagId).then(collection => {
  // Fetch up to 200 tasks, using multiple pages if necessary
  collection.fetch(200).then(tasks => {
    console.log(tasks);
  });
});

Streaming

You can also construct a stream from a collection. This will transparently (and lazily) fetch the items in the collection in pages as you iterate through them.

client.tasks.getTasksForTag(tagId).then(collection => {
  collection.stream().on('data', task => {
    console.log(task);
  });
});

Debugging

To quickly debug raw requests. Set debug to true on the Asana dispatcher.

client.dispatcher.debug(true);

We use the request library under the hood, and this is equivalent to setting request.debug = true;

Error handling

In any request against the Asana API, there a number of errors that could arise. Those are well documented in the [Asana API Documentation][api-reference], and are represented as exceptions under the namespace Asana.errors.

Options

To add global headers (like for our deprecation framework), you add them to the client.

    asana.Client.create({"defaultHeaders": {"asana-enable": "string_ids,new_sections"}});

Asana Change Warnings

You will receive warning logs if performing requests that may be affected by a deprecation. The warning contains a link that explains the deprecation.

If you receive one of these warnings, you should:

  • Read about the deprecation.
  • Resolve sections of your code that would be affected by the deprecation.
  • Add the deprecation flag to your "asana-enable" header.

If you would rather suppress these warnings, you can do the following:

    asana.Client.create({"logAsanaChangeWarnings": false});

Examples

Various examples are in the repository under examples/, but some basic concepts are illustrated here.

Find some incomplete tasks assigned to me that are new or marked for today in my default workspace

const Asana = require('asana');
const util = require('util');

// Using a PAT for basic authentication. This is reasonable to get
// started with, but Oauth is more secure and provides more features.

var client = Asana.Client.create().useAccessToken(process.env.ASANA_PAT);

client.users.me()
  .then(user => {
    const userId = user.gid;
    // The user's "default" workspace is the first one in the list, though
    // any user can have multiple workspaces so you can't always assume this
    // is the one you want to work with.
    const workspaceId = user.workspaces[0].gid;
    return client.tasks.getTasks({
      assignee: userId,
      workspace: workspaceId,
      completed_since: 'now',
      opt_fields: 'id,name,assignee_status,completed'
    });
  })
  .then(response => {
    // There may be more pages of data, we could stream or return a promise
    // to request those here - for now, let's just return the first page
    // of items.
    return response.data;
  })
  .filter(task => {
    return task.assignee_status === 'today' ||
      task.assignee_status === 'new';
  })
  .then(list => {
    console.log(util.inspect(list, {
      colors: true,
      depth: null
    }));
  })
  .catch(e => {
    console.log(e);
  });

Documentation

The code is thoroughly documented with JSDoc tags. The [Official Asana Documentation][asana-doc] is a great resource, since this is just a thin wrapper for the API.

Contributing

Feel free to fork and submit pull requests for the code! Please follow the existing code as an example of style, and make sure that all your code passes lint and tests.

For a sanity check:

git clone [email protected]:Asana/node-asana.git
cd node-asana
npm install
npm test

Code generation

The specific Asana resource classes within the gen folder (Tag, Workspace, Task, etc.) are generated code, hence they shouldn't be modified by hand.

See our [openapi spec][https://github.com/Asana/developer-docs/blob/master/defs/asana_oas.yaml] and swagger for details.

Deployment

Repo Owners Only. Take the following steps to issue a new release of the library.

Automatic Deployment

  1. Merge in the desired changes into the master branch and commit them.
  2. Clone the repo; work on master.
  3. Bump the package version to indicate the semantic version change, using one of: gulp bump-patch, gulp bump-minor, or gulp bump-major (NOTE: If this is your first time running gulp please install gulp globally using npm i -g gulp)
  4. Push changes to origin, including tags: git push --tags origin master:master

Manual Deployment

  1. Merge in the desired changes into the master branch and commit them.
  2. Clone the repo, work on master.
  3. Edit package version in package.json, bower.json and VERSION to indicate the semantic version change.
  4. Commit the change
  5. Tag the commit with v plus the same version number you set in the file. git tag v1.2.3
  6. Push changes to origin, including tags: git push --tags origin master:master

GitHub Actions will automatically build and deploy the tagged release.

🎗️ Make sure to edit the new release description on GitHub after it has been deployed. Please use bullet points to indicate notable changes since the last version.

More Repositories

1

Drawsana

An open source library that lets your users draw on things - mark up images with text, shapes, etc.
Swift
645
star
2

typed-react

A binding layer between React and TypeScript
TypeScript
373
star
3

kraken

Distributed Pubsub Server for Realtime Apps
Erlang
335
star
4

python-asana

Official Python client library for the Asana API v1
Python
280
star
5

Chrome-Extension-Example

Sample application illustrating use of the Asana API
JavaScript
232
star
6

php-asana

Official PHP client library for the Asana API v1
PHP
135
star
7

locheck

Validate iOS, Android, and Mac localizations. Find errors in .strings, .stringsdict, and strings.xml files.
Swift
97
star
8

bazels3cache

Small web server for a Bazel cache, proxies to S3; allows Bazel to work offline; async uploads to make Bazel faster
TypeScript
79
star
9

ruby-asana

Official Ruby client library for the Asana API v1
Ruby
76
star
10

bazeltsc

TypeScript compiler that knows how to run as a Bazel "persistent worker"
TypeScript
39
star
11

java-asana

Official Java client library for the Asana API v1
Java
35
star
12

create-app-attachment-github-action

TypeScript
33
star
13

devrel-examples

A place to share some examples from our Developer Relations team for commonly-asked-about workflows.
Python
27
star
14

comment-on-task-github-action

TypeScript
25
star
15

asana2sql

Utility for exporting Asana data to SQL databases
Python
23
star
16

api-explorer

React component to explore the Asana API
TypeScript
19
star
17

omniauth-asana

Official Asana strategy for OmniAuth
Ruby
16
star
18

SGTM

Python
14
star
19

asana-api-meta

Metadata for Asana API for generating client libraries and documenation
HTML
11
star
20

kraken-node-client

A nodejs client for the Kraken pubsub server
JavaScript
10
star
21

tsutil

TypeScript Utility Data Structures
TypeScript
9
star
22

node-asana-phrase

A random error phrase generator used to create memorable error codes, as used by Asana.
JavaScript
9
star
23

typescript-namespace-imports-vscode-plugin

A VSCode plugin that makes it easier to automatically include TypeScript namespace imports.
TypeScript
6
star
24

asana-shift

A small node script which uses the Asana API to shift all task start and due dates relative to a project's due date.
TypeScript
5
star
25

markdown-formatter

JavaScript
5
star
26

random-one-on-one

Python
5
star
27

app-components-example-app

app-components-example-app
JavaScript
4
star
28

ohmega

The Asana Ohmega process automation toolkit
Python
4
star
29

openapi

Python
4
star
30

sshca

Certificate authority for OpenSSH
Python
3
star
31

jira-server-plugin

Asana for Jira Server
3
star
32

node-asana-preview

A preview of Asana's new node client library
JavaScript
3
star
33

app-components-rule-action-example-app

JavaScript
3
star
34

python-asana-preview

A preview of Asana's new python client library
Python
3
star
35

node-sync-to-github

A node library that makes it easy to sync a directory of files to a GitHub repo using the GitHub API
JavaScript
3
star
36

deprovision_inactive_guests

A small script which uses the Asana API to remove external users (ie without a company email) from an organization if they haven't logged in for 30 days
JavaScript
2
star
37

archie

Python
2
star
38

formula-custom-fields

JavaScript
1
star
39

node-linux-fork

An implementation of fork() for Node.JS in Linux (requires a custom Node.JS build)
C++
1
star