The `subtasks` field on tasks is being deprecated

That’s actually only a small percentage of the number of active apps. We need to get more people on the community!

1 Like

Just received the email about this change.

Our organization uses subtasks heavily, and we’re using the API to visualize them. If I understand this change, it means that what we’ve been doing in one request (grabbing all tasks and their immediate subtasks) is going to become 40-50 requests. Is that accurate?

Furthermore, the events API doesn’t say it works on subtasks, and I see no push mechanism, so it appears that we have no choice but to poll using all 40-50 requests each time. Is that accurate as well?

3 Likes

Our customers at Everhour also use subtasks a lot.

Everhour provides time tracking possibilities for Asana tasks and subtasks. But now it will require us do much more requests to sync all project tasks.

Do you have alternative option API to get all project tasks & subtasks?

3 Likes

Hi @Brian_Victor, you are correct that it will require more API calls to get all of the subtasks in a project. Without knowing your exact workflow and how deep your subtasks go, I’m not certain how many more requests it will take.

While it was never meant to be supported, you can currently get all of the tasks and subtasks in a project with a single call (GET /projects/project-id/opt_expand=subtasks+). Unfortunately, this expansion is causing stability issues for the API. Once the subtasks field is deprecated, you would need to make this request using the tasks field num_subtasks instead of subtasks+. You can then make subsequent requests on each task that contains subtasks until "num_subtasks": 0.

You can reduce the number of requests required by using the batch API.

Can you tell me a bit more about what you’re trying to achieve with events? You can request events on a project and the stories will bubble up from tasks and subtasks (and all nested subtasks). You can also get events on subtasks directly (this is admittedly a bit confusing as the docs say you can only target projects and tasks, but subtasks are actually tasks in the data model that just have parents that are other tasks. If you query a subtask, you will notice that it says "resource_type": "task").

I’m sorry that this change is frustrating (and somewhat confusing) to have to implement. Let us know if there is anything we can do to make it less painful.

Best,
Jeff

1 Like

Hi @Yury,

Thanks for reaching out and sorry that we have to make this change. The new approach for getting all tasks and subtasks in a project using the num_subtasks field instead of subtasks is actually not that different. We have always required pagination, we are now just also requiring it for accessing lower levels of objects. Without getting too far into the weeds, a main reason for this change is because the potential fan-out of subtask expansion is essentially unbounded (i.e. one task can contain nearly infinite subtasks and fetching these types of tasks is causing stability issues that result in us having to ban apps).

Using num_subtasks, the batch API, and events/webhooks, developers can still reasonably fetch (and stay in sync with) all of the tasks and subtasks in a project.

Best,
Jeff

1 Like

@Jeff_Schneider I was asking about events as a way to avoid polling the entire project just to see if anything had changed. From what you say, it appears they might work for that. It would still be nice to have a push mechanism. (Webhooks seem to require running a server and forwarding the pushes to the clients.)

What about a way to request a flattened view of tasks? It would be a dramatic improvement if I could request all tasks and subtasks in the project and reassemble the structure on the client. Still more of a pain than the status quo, but not nearly as bad as the suggested 1+N workaround.

@Brian_Victor As you point out, we have two options for getting changes:

  1. Poll for events on a project, task or subtask (note: that events bubble up, so changes to tasks or subtasks would trigger events on a project).
  2. Get events sent to you with webhooks.

Webhooks do add complexity and require that you have a server to receive them. If your app needs to keep data synced in real time then webhooks are a good option. If changes don’t need to be reflected in real time, fetching events is likely the best approach.

We want to avoid developers being able to get all tasks and subtasks in a single request (that’s one of the reasons we are moving away from subtask expansion). A single task can have an infinite number of subtasks. When apps request tasks with too many subtasks, it causes API stability issues, which causes our API engineers to get paged and they have to ban the app. This is a poor outcome for everyone.

You want to avoid flattened task requests even with pagination and perhaps depth limits? I understand not wanting unbounded responses, but I feel like there must be a way to avoid that without also requiring an explosion of requests. I’m happy to explore ideas with you if you’re open to looking for such a way.

To elaborate on our use case, we have about 40-50 active tasks at a time on the current iteration’s project. Each of those has an average of about 4 subtasks. Currently I can easily get everything in one request. If I had a flattened view, and the limit were 100 at a time, I would require 2, which is tenable. Requesting all subtasks manually requires 41-51 requests. When I’m on mobile and it takes a few seconds to complete one request, that turns into a multiple minute load time. That’s not something that’s going to work.

Hi, we are using lot of these “hidden undocumented sub-queries”, because we don’t know from the root if the container have or not subitems.
This new num_subtasks field is totally welcome.
May I suggest to also add
num_attachments
num_(any-subitem-that-require-additional-query)!

2 Likes

I just found an issue… if I query my task using opt_fields parameter, I can get this new field.
But, it is not included in the default fields, if I query my task without parameters, like this:
GET https://app.asana.com/api/1.1/tasks/xxxxxxx
I have num_hearts, num_likes, but no num_subtasks.

This is “as designed” - the num_subtasks field is documented as an opt-in field requiring that you ask for it.

2 Likes

Thank you @Phil_Seeman, I just read that in the documentation page!
It’s the only field with that behavior. But, the documentation is not always 100% accurate, as we get some undocumented fields in return of a single task, like “num_hearts” (number), “hearted” (bool), “hearts” (array)… that’s why I took time to mention that we should get num_subtasks also!

There are a number of fields that are not included by default on tasks, such as html_notes and dependencies. The reason we exclude these fields by default is because they involve extra queries and computation to generate, which slow down our response times. We don’t want to unnecessarily slow down our API for users who don’t actually care about these fields, so we require developers that do care about them to explicitly select them with opt_fields.

Hearts and the associated fields are remnants from the rename from “hearts” to “likes.” We didn’t have the deprecation framework in place at the time and were unable to properly remove these fields. In the future, we may run a deprecation to clean this up, but that would cause work for some developers without any benefit to them.

2 Likes

Hi – is there an update timeline for when the subtasks field will be deprecated?

Hi @Ron_Yang, we are still working with some partners to help them migrate away from using this field. We do not currently have an estimate for when we will fully remove it from the API, but we are encouraging all developers to move away from it as soon as they can.

I assume from the lack of response to my suggestion that depth limits are a non-starter.

I had some time today to try to come up with an alternate approach. Using events at first glance seemed to be a good idea, but I pretty quickly hit some snags. First, they’re not supported in @types/asana, but I can work around that with some casts to any. Second, and more importantly, changes to tasks don’t give me enough information to replicate server changes in my application. It’ll work fine if the name is changed, but the event won’t tell me if the completion state changed, or if it was reassigned.

There’s more information available in the “story” changes, but those seem to be very hard to reconcile since multiple story changes can be produced for a single task change.

The other approach I’ve thought of would be to reload the task entirely when I detect any change to it. It would probably work at the cost of extra round trips and request quota hits.

Am I barking up the wrong tree? Is there a simple solution I’m missing to keep the client-side tasks in sync with the server?

Hi @Brian_Victor,

Yes, even depth limits are insufficient here. A single task could have hundreds or thousands of subtasks so limiting queries even just to one level of subtasks can still put significant load on our systems.

We’re aware that event streams (and webhooks) lack enough information to understand what properties of an object changed (and thus what properties you need to update to stay in sync) and we’re actively working on improvements to them. We’ll be communicating more about this work sometime in the next two months. Until then, the most robust strategy to stay perfectly in sync is to listen for events (either through event streams or webhooks) and then fetch the full object that changed.

1 Like

Hi Jeff & Joe,

Wondering if I could get some advice on the best way to pull the information I need. I really need to pull the assignee of the subtask since we have projects with multiple people working on a task but no way to report / assign that other than with subtasks. As of right now would it be best to follow the points below?

Would this also be the best way to retrieve story information?

Thank you!

Hi @Jill_H, the only supported way to fetch subtasks is through the GET /tasks/task-id/subtasks endpoint. You can use our opt_fields feature to include the subtasks’ assignees in the response.

To fetch stories for a task, you’ll need to use GET /tasks/task-id/stories for each individual task.

1 Like

2 posts were split to a new topic: How to get the tasks in a project without also getting the sections