Java client library for the Asana API.
If you use Maven to manage dependencies you can include the "asana" artifact by adding it as a dependency in your pom.xml
file.
<dependency>
<groupId>com.asana</groupId>
<artifactId>asana</artifactId>
<version>0.10.12</version>
</dependency>
Or, you can build the artifact and install it to your local Maven repository:
mvn install
mvn compile
mvn test
Be sure to run mvn compile
first.
Set the ASANA_ACCESS_TOKEN, ASANA_CLIENT_ID, and ASANA_CLIENT_SECRET environment variables. The app's redirect URL should be set to "urn:ietf:wg:oauth:2.0:oob" for command line scripts examples, and "http://localhost:5000/auth/asana/callback" for the server example.
export ASANA_ACCESS_TOKEN="X"
export ASANA_CLIENT_ID="X"
export ASANA_CLIENT_SECRET="X"
Web application example:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExampleServer"
OAuth command line script example:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExampleOAuth"
Personal access token command line script example:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExamplePersonalAccessToken"
Demo create a task and upload an attachment:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExampleCreateTaskAndUpload"
Demo create project and stream change events:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExampleCreateProjectAndStreamEvents"
Create a client using a personal access token:
Client client = Client.accessToken("ASANA_ACCESS_TOKEN");
Asana supports OAuth 2. java-asana
handles some of the details of the OAuth flow for you.
Create a client using your OAuth Client ID and secret:
OAuthApp app = new OAuthApp(
"ASANA_CLIENT_ID",
"ASANA_CLIENT_SECRET",
"urn:ietf:wg:oauth:2.0:oob"
);
Client client = Client.oauth(app);
Redirect the user to the authorization URL obtained from the client's session
object:
String url = app.getAuthorizationUrl()
getAuthorizationUrl()
takes an optional state parameter to be used for preventing CSRF attacks:
String state = UUID.randomUUID().toString();
String url = app.getAuthorizationUrl(state);
When the user is redirected back to your callback, check the state
URL parameter matches, then pass the code
parameter to obtain a bearer token:
if (request.param("state").equals(state)) {
String token = app.fetchToken(request.params("code"));
// ...
} else {
// error! possible CSRF attack
}
Note: if you're writing a non-browser-based application (e.x. a command line tool) you can use the special redirect URI urn:ietf:wg:oauth:2.0:oob
to prompt the user to copy and paste the code into the application.
The client's methods are divided into several resources: attachments
, customFields
, customFieldSettings
, events
, jobs
, organizationExports
, portfolios
, portfolioMemberships
, projects
, projectMemberships
, projectStatuses
, stories
, tags
, tasks
, teams
, users
, userTaskLists
, webhooks
, and workspaces
.
Request methods use the "builder" pattern to set query string or JSON body parameters, and various request options, so a request must be initated using the execute
or executeRaw
methods:
Methods that return a single object return that object directly:
User me = client.users.me().execute();
System.out.println("Hello " + me.name);
String workspaceId = me.workspaces.get(0).gid;
Project project = client.projects.createInWorkspace(workspaceId)
.data("name", "new project")
.execute();
System.out.println("Created project with id: " + project.gid);
Methods that return multiple items (e.x. findAll
) return an Iterable
object. See the "Collections" section
Various options can be set globally on the Client.DEFAULTS
object, per-client on client.options
, or per-request using the option
method. For example:
// global:
Client.DEFAULTS.put("page_size", 1000);
// per-client:
client.options.put("page_size", 1000);
// per-request:
client.tasks.findAll().query("project", 1234).option("page_size", 1000).execute();
base_url
(default: "https://app.asana.com/api/1.0"): API endpoint base URL to connect tomax_retries
(default: 5): number to times to retry if API rate limit is reached or a server error occures. Rate limit retries delay until the rate limit expires, server errors exponentially backoff starting with a 1 second delay.fields
andexpand
: array of field names to include in the response, or sub-objects to expand in the response. For example.option("fields", Arrays.asList("followers", "assignee"))
. See API documentation
Collections (methods returning an array as it's 'data' property):
item_limit
(default: -1): limits the total number of items of a collection to return (spanning multiple requests in the case of an iterator).page_size
(default: 50): limits the number of items per page to fetch at a time when using an iterator.offset
: offset token returned by previous calls to the same method, when usingexecuteRaw()
(inresponse.nextPage.offset
)
Events:
poll_interval
(default: 5): polling interval for getting new events via anEventsRequest
iterator (e.x.for (Event event : client.events.get(resourceId)) { ... }
)sync
: sync token returned by previous calls toevents.get
(e.x.client.events.get(resourceId, syncToken).executeRaw().sync
)
To add global headers (like for our deprecation framework), you simply add them to the client.
client.headers.put("asana-enable", "string_ids");
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.
You can place it on the client for all requests.
client.headers.put("asana-enable", "string_ids,new_sections");
or
client.headers.put("asana-disable", "string_ids");
If you would rather suppress these warnings, you can set
client.logAsanaChangeWarnings = false;
APIs that return a collection return a CollectionsRequest, which is an iterable:
Iterable<Workspace> workspaces = client.workspaces.findAll();
for (Workspace workspace: workspaces) {
System.out.println("Workspace: " + workspace.name);
}
Internally the iterator may make multiple HTTP requests, with the number of requested results per page being controlled by the page_size
option.
You can also use the raw API to fetch a page at a time:
String offset = null;
while (true) {
ResultBodyCollection<Workspace> page = client.workspaces.findAll()
.option("offset", offset)
.option("limit", 2)
.executeRaw();
System.out.println("received " + page.data.size() + " results");
if (page.nextPage != null) {
offset = page.nextPage.offset;
} else {
break;
}
}
To deploy a new version to the Maven Central Repository, you can run:
mvn deploy -P release --settings settings.xml
Before you do this, you must set a few environment variables to authenticate:
- Maven credentials:
MAVEN_USERNAME
andMAVEN_PASSWORD
- GPG keyname and password:
MAVEN_GPG_KEYNAME
andMAVEN_GPG_PASSWORD
You can log in to verify the new version landed, and after some time it will be deployed to maven.