Asana Node.js Client Library

repository·master·Indexed 43 days ago

https://github.com/asana/node-asana

A Node.js and browser client library (version 3.2.0) for interacting with the Asana API. It provides programmatic access to Asana resources such as tasks, users, projects, portfolios, and tags through specialized API classes like TasksApi, UsersApi, and ProjectsApi.

Tokens
233.3K
Snippets
361
Records
399
Agent score
53%

What's inside Asana

  1. Understand the API base URI for node-asana

    master
    When using the node-asana client, all API endpoint URIs are relative to the base URL: https://app.asana.com/api/1.0. This base URL is used for all requests made through the library to interact with the Asana API.
  2. Use `opt_fields` to request specific resource properties

    master

    By default, endpoints that return arrays of results (such as getTasks or getProjects) return a compact version of the objects (e.g., TaskCompact). To retrieve additional properties, use the opt_fields parameter in your request options. This parameter accepts a comma-separated string of the field names you wish to include in the response.

    Using opt_fields is essential for retrieving nested data like assignee.name, custom_fields, or memberships.project.name.

  3. How pagination works with Collection objects

    master

    By default, endpoints that return an array of results return a Collection object. This object includes a nextPage() method used to fetch subsequent pages of results.

    Requirements for pagination:

    • You must provide a limit query parameter in your initial request.
    • The limit value must be between 1 and 100.

    If you attempt to request an endpoint with more than 1000 results without pagination, you may receive the error: "The result is too large. You should use pagination (may require specifying a workspace)!"

    const Asana = require('asana');
    
    let client = new Asana.ApiClient();
    client.authentications.token.accessToken = '<YOUR_ACCESS_TOKEN>';
    
    let tasksApiInstance = new Asana.TasksApi(client);
    let opts = {
        "project": "<YOUR_PROJECT_GID>",
        "limit": 100,
    };
    
    async function getAllTasks(opts) {
        let tasks = await tasksApiInstance.getTasks(opts).then(async (response) => {
            let result = [];
            let page = response;
            while(true) {
                // Add items on page to list of results
                result = result.concat(page.data);
                // Fetch the next page
                page = await page.nextPage();
                // If there is no data in the next page break from the loop
                if (!page.data) {
                    break;
                }
            }
            return result;
        }, (error) => {
            console.error(error.response.body);
        });
        console.log('Tasks: ' + JSON.stringify(tasks, null, 2));
    }
    
    getAllTasks(opts);
  4. How to create a webhook and complete the handshake

    master

    Establishing a webhook is a two-part process that requires your server to handle requests asynchronously.

    1. Initiation: Send a POST request to /webhooks with the desired resource and target URL.
    2. Handshake: As part of the creation request, Asana will send a test POST to your target URL containing an X-Hook-Secret header.
    3. Confirmation: Your server must respond to this test POST with a 200 OK or 204 No Content status and return the exact same X-Hook-Secret header value.

    If you do not acknowledge the handshake while the initial POST request is still in-flight, the webhook setup will fail. It is strongly recommended to store the X-Hook-Secret returned in the final response to verify future webhook event signatures.

    Note: Invalid hostnames like localhost will result in a 403 Forbidden error.

    # 1. Initiation
    curl -H "Authorization: Bearer <personal_access_token>" \
     -X POST https://app.asana.com/api/1.0/webhooks \
     -d "resource=8675309" \
     -d "target=https://example.com/receive-webhook/7654"
    
    # 2. Handshake sent by Asana to your target
    # POST /receive-webhook/7654
    # X-Hook-Secret: b537207f20cbfa02357cf448134da559e8bd39d61597dcd5631b8012eae53e81
    
    # 3. Your required response
    # HTTP/1.1 200
    # X-Hook-Secret: b537207f20cbfa02357cf448134da559e8bd39d61597dcd5631b8012eae53e81
  5. Configure fields and filters for resource exports

    master

    When using createResourceExport, you can control the scope and content of the export using the body payload:

    • Specifying Fields: Use the fields parameter to include only specific fields. This follows the standard Asana fields parameter logic and is recommended for performance optimization.
    • Filtering Resources: You can apply filters using export_request_parameters. To achieve a disjunction (OR logic) of two or more filters, provide multiple export_request_parameters for the same resource type, each with different filters.
      • Note: Using multiple filters for the same resource may result in duplicate resources being returned in the export.
  6. Initialize the Asana ApiClient and authenticate

    master

    To interact with the Asana API, you must first instantiate an ApiClient, set your access token via the authentications.token.accessToken property, and then pass that client to specific API instances (e.g., UsersApi, TasksApi).

    const Asana = require('asana');
    
    let client = new Asana.ApiClient();
    client.authentications.token.accessToken = '<YOUR_ACCESS_TOKEN>';
    
    // Pass the client to an API instance
    let usersApiInstance = new Asana.UsersApi(client);
  7. How to get events using sync tokens

    master

    To subscribe to events for a specific resource (task or project), you must use a sync token.

    1. Initial Sync: Make an initial call to getEvents with an empty sync parameter. If the request fails with a specific error, the error response body will contain the required sync token.
    2. Polling: Use the sync token in subsequent requests to fetch only new events.
    3. Updating Token: After every successful event fetch, update your sync token using the sync value provided in the response (often found in result._response.sync or via a 412 error response body) to ensure you are tracking the latest changes.
    const Asana = require('asana');
    
    let client = new Asana.ApiClient();
    client.authentications.token.accessToken = '<YOUR_ACCESS_TOKEN>';
    
    let eventsApiInstance = new Asana.EventsApi(client);
    let resource = "<YOUR_TASK_OR_PROJECT_GID>";
    let opts = {
        "sync": ""
    };
    const timeouts = 5000
    
    const setSyncToken = async () => {
        await eventsApiInstance.getEvents(resource, opts).then((result) => {
            console.log(JSON.stringify(result.data, null, 2));
        }, (error) => {
            let syncToken = error.response.body.sync;
            opts['sync'] = syncToken;
        });
    }
    
    const getEvents = async () => {
        await setSyncToken();
        while(true) {
            await eventsApiInstance.getEvents(resource, opts).then((result) => {
                console.log(JSON.stringify(result.data, null, 2));
                opts['sync'] = result._response.sync;
            }, (error) => {
                if (error.status === 412) {
                    let syncToken = error.response.body.sync;
                    opts['sync'] = syncToken;
                } else {
                    console.error(error.response.text);
                }
            });
            await new Promise(resolve => setTimeout(resolve, timeouts));
        }
    }
    
    getEvents();
  8. Filter search results by custom task types

    master

    You can filter tasks by their custom task status option using the custom_types.{gid}.custom_type_status_option.gid parameter.

    Requirements

    • resource_subtype=custom must be set.
    • Only one custom_types.* parameter may be specified per request.
    • The provided custom task type GID must reference a valid custom object type.
    • The status option GID must be a valid option for that type's status field.
    • Constraint: Cannot be combined with custom_fields.{status_field_gid}.value if that field belongs to the same custom task type.

    Example

    To find custom tasks of type 12345 with status option 67890: custom_types.12345.custom_type_status_option.gid=67890&resource_subtype=custom

    // Example configuration for custom task type search
    let opts = {
        'resource_subtype': 'custom',
        'custom_types.12345.custom_type_status_option.gid': '67890'
    };
  9. Debug Swagger Codegen template data using debug flags

    master

    When customizing Mustache templates (like api.mustache), you can use debug flags during the CLI execution to inspect the objects and data being passed to the template engine. This helps you identify which keys and values are available for generation.

    Available Debug Flags

    • -DdebugSwagger: Prints the OpenAPI Specification as interpreted by the codegen.
    • -DdebugModels: Prints models passed to the template engine.
    • -DdebugOperations: Prints operations passed to the template engine.
    • -DdebugSupportingFiles: Prints additional data passed to the template engine.

    Example: Debugging Operations

    To see the data available for operations, add the -DdebugOperations flag to your execution command:

    java -DdebugOperations -cp /path/to/swagger-codegen-cli.jar:/path/to/your.jar io.swagger.codegen.v3.cli.SwaggerCodegen -l AsanaPythonClientCodegen -i /path/to/swagger.yaml -o ./test
    java -DdebugOperations -cp /path/to/swagger-codegen-cli.jar:/path/to/your.jar io.swagger.codegen.v3.cli.SwaggerCodegen -l AsanaPythonClientCodegen -i /path/to/swagger.yaml -o ./test
  10. Install the Asana client for the browser

    master

    To use the Asana client directly in a browser, include the minified script from the GitHub releases.

    Warning: Be extremely careful not to expose your access token in client-side code.

    <script src="https://github.com/Asana/node-asana/releases/download/v3.2.0/asana-min.js"></script>
  11. Use the Swagger Codegen boilerplate to generate a client library

    master

    This project serves as a boilerplate for generating custom client libraries using Swagger. It provides the basic plumbing required to start a custom generator, but requires manual modifications to the generator logic and templates to function as a specific client library.

    Project Structure

    A generated setup typically includes:

    • pom.xml: The build script.
    • src/main/java/.../AsanaPythonClientCodegenGenerator.java: The core generator file where logic is implemented.
    • src/main/resources/AsanaPythonClientCodegen/: The directory containing Mustache template files.
    • src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig: Service registration for the codegen engine.
    # Typical project structure
    .
    |- README.md
    |- pom.xml
    |-- src
    |--- main
    |---- java
    |----- com.asana.codegen.AsanaPythonClientCodegenGenerator.java
    |---- resources
    |----- AsanaPythonClientCodegen
    |----- META-INF
    |------ services
    |------- io.swagger.codegen.CodegenConfig