get_task API won't return a JSON with double quotes and only required fields values

I just picked the proposed code from this page for getting a task using API: Get a task?

I didn’t change anything except I limited optional fields to just one field.

Not only it returns all fields with just None values, it also uses single quotes and so not parsable as JSON.

{‘data’: {‘actual_time_minutes’: None,
‘approval_status’: None,
‘assignee’: None,
‘assignee_section’: None,
‘assignee_status’: None,
‘completed’: None,
‘completed_at’: None,
‘completed_by’: None,
‘created_at’: None,
‘created_by’: None,
‘custom_fields’: None,
‘dependencies’: None,
‘dependents’: None,
‘due_at’: None,
‘due_on’: None,
‘external’: None,
‘followers’: None,

Is there a way to get a limited response in a JSON format?

Hi @Tetiana_Kushla,

The Asana API definitely returns double quotes. For example, here’s a task I just retrieved using the interactive API docs:

{
  "data": {
    "gid": "1120505760233870",
    "due_on": null,
    "name": "Fix the frammitz button"
  }
}

However you’re ending up with single quotes must be coming from something on your end.

Can you post your code so we can see for both this one and the issue above? You can definitely use opt_fields to limit the output (in my example above, I used opt_fields=name,due_on). FYI if you’re referring to one custom field, you can’t filter to a subset of custom fields.

Thanks, Phil.

@Tetiana_Kushla, can you clarify - are you using the latest Asana Python SDK + code snippets? We recently launched a new Python SDK in beta and are collecting feedback on it.

I am not sure about Asana Python SDK + code snippets, I am not that experienced in Python, I am just looking for ways to get extra data which does not come though PowerBI connector.

So I copied the following code:

import asana
from asana.rest import ApiException
from pprint import pprint

# Configure OAuth2 access token for authorization: oauth2
configuration = asana.Configuration()
configuration.access_token = '<YOUR_PERSONAL_ACCESS_TOKEN>'
api_client = asana.ApiClient(configuration)

# create an instance of the API class
api_instance = asana.TasksApi(api_client)
task_gid = '321654' # str | The task to operate on.
opt_fields = ["actual_time_minutes","approval_status","assignee","assignee.name","assignee_section","assignee_section.name","assignee_status","completed","completed_at","completed_by","completed_by.name","created_at","created_by","custom_fields","custom_fields.asana_created_field","custom_fields.created_by","custom_fields.created_by.name","custom_fields.currency_code","custom_fields.custom_label","custom_fields.custom_label_position","custom_fields.date_value","custom_fields.date_value.date","custom_fields.date_value.date_time","custom_fields.description","custom_fields.display_value","custom_fields.enabled","custom_fields.enum_options","custom_fields.enum_options.color","custom_fields.enum_options.enabled","custom_fields.enum_options.name","custom_fields.enum_value","custom_fields.enum_value.color","custom_fields.enum_value.enabled","custom_fields.enum_value.name","custom_fields.format","custom_fields.has_notifications_enabled","custom_fields.is_formula_field","custom_fields.is_global_to_workspace","custom_fields.is_value_read_only","custom_fields.multi_enum_values","custom_fields.multi_enum_values.color","custom_fields.multi_enum_values.enabled","custom_fields.multi_enum_values.name","custom_fields.name","custom_fields.number_value","custom_fields.people_value","custom_fields.people_value.name","custom_fields.precision","custom_fields.resource_subtype","custom_fields.text_value","custom_fields.type","dependencies","dependents","due_at","due_on","external","external.data","followers","followers.name","hearted","hearts","hearts.user","hearts.user.name","html_notes","is_rendered_as_separator","liked","likes","likes.user","likes.user.name","memberships","memberships.project","memberships.project.name","memberships.section","memberships.section.name","modified_at","name","notes","num_hearts","num_likes","num_subtasks","parent","parent.created_by","parent.name","parent.resource_subtype","permalink_url","projects","projects.name","resource_subtype","start_at","start_on","tags","tags.name","workspace","workspace.name"] # list[str] | This endpoint returns a compact resource, which excludes some properties by default. To include those optional properties, set this query parameter to a comma-separated list of the properties you wish to include. (optional)

try:
    # Get a task
    api_response = api_instance.get_task(task_gid, opt_fields=opt_fields)
    pprint(api_response)
except ApiException as e:
    print("Exception when calling TasksApi->get_task: %s\n" % e)

I pasted it into an empty Python project in PyCharm, and limited the fields to pull (obviously I had to install asana and pprint packages for first). So my code is exactly this:

import asana
from asana.rest import ApiException
from pprint import pprint


if __name__ == '__main__':
    configuration = asana.Configuration()
    configuration.access_token = 'my personal token here'
    api_client = asana.ApiClient(configuration)

    # create an instance of the API class
    api_instance = asana.TasksApi(api_client)
    task_gid = 'some specific task id here'  # str | The task to operate on.
    opt_fields = ["tags", "tags.name"]
    try:
        # Get a task
        api_response = api_instance.get_task(task_gid, opt_fields=opt_fields)
        pprint(api_response)
    except ApiException as e:
        print("Exception when calling TasksApi->get_task: %s\n" % e)

But this is what it returns:

{'data': {'actual_time_minutes': None,
          'approval_status': None,
          'assignee': None,
          'assignee_section': None,
          'assignee_status': None,
          'completed': None,
          'completed_at': None,
          'completed_by': None,
          'created_at': None,
          'created_by': None,
          'custom_fields': None,
          'dependencies': None,
          'dependents': None,
          'due_at': None,
          'due_on': None,
          'external': None,
          'followers': None,
          'gid': '55555555......my actual task id here',
          'hearted': None,
          'hearts': None,
          'html_notes': None,
          'is_rendered_as_separator': None,
          'liked': None,
          'likes': None,
          'memberships': None,
          'modified_at': None,
          'name': None,
          'notes': None,
          'num_hearts': None,
          'num_likes': None,
          'num_subtasks': None,
          'parent': None,
          'permalink_url': None,
          'projects': None,
          'resource_subtype': None,
          'resource_type': None,
          'start_at': None,
          'start_on': None,
          'tags': [],
          'workspace': None}}

Sorry for bad formatting, it is almost unreadable, but I had no idea the markup will do so. And I cannot edit the post :frowning:

(I edited your post so the formatting looks better :slight_smile: )

2 Likes

Hi @Tetiana_Kushla,

Thanks for sharing more detail and confirming the Python bit. For what it’s worth, I think if you’re not specifying the version, it’s likely that you’re getting the latest / beta version I mentioned.

I don’t have a Python environment handy to dig into the exact snippet, but if things are working correctly, the optional fields you requested should be populated in a Class object that represents the Task, the rest of the fields would be None (basically Python’s version of null).

So in this case, I would expect tags to contain a list of tag names based on the opt_fields you requested. The fact that it’s an empty list and not None seems like a good sign. Do you know for certain that the task you are fetching has tags? If not, that could be the reason for the empty list. If you’re certain it has tags, does including only the tags as an opt_field change the response? If not, it could be a bug in the SDK for us to look into or a quirk with the request that I’m not seeing.

In terms of the JSON, the single quotes could be that it’s a pretty print of a Python object rather than JSON? It’s been a while since I’ve manipulated JSON in Python, so I don’t want to lead you astray, but it might require some additional handling like json.dumps(api_response) to get into JSON?

Hope that helps some.

Thanks again,
John

Hi @Tetiana_Kushla,

@John_Baldo is right our new python client library (v4.X.X) returns a <class 'asana.models.task_response_data.TaskResponseData'> object for the api_response = api_instance.get_task(task_gid, opt_fields=opt_fields) method call.

The reason why you are getting all fields back even though you requested just for one field in opt_fields is because of how the (v4.X.X) library works. This version of the library is making an HTTP call using a request library (urllib3) then tries to map the values of the response to a TaskResponseData class which contains the full schema for a task. Notice that only the values for the opt_fields you requested is populated in the api_response and the rest is None.

From here if you want to get the double quotes from the response you’ll have to:

Convert the api_response object from <class 'asana.models.task_response_data.TaskResponseData'> to a python dict then import json library and convert that python dict to a JSON string. All together it looks like:

import asana
from asana.rest import ApiException
import json
from pprint import pprint

# Configure OAuth2 access token for authorization: oauth2
configuration = asana.Configuration()
configuration.access_token = "<YOUR_ASANA_PERSONAL_ACCESS_TOKEN>"

# Create an instance of the API class
api_instance = asana.TasksApi(asana.ApiClient(configuration))
task_gid = '<TASK_GID>'
opt_fields = ["created_by","name"]

try:
    # Get a task
    api_response = api_instance.get_task(task_gid, opt_fields=opt_fields)
    api_response_json = json.dumps(api_response.to_dict())
    pprint(api_response_json)
except ApiException as e:
    print("Exception when calling TasksApi->get_task: %s\n" % e)

The results will look like this:

'{"data": {"gid": "<TASK_GID>", "resource_type": null, "name": "task '
 '6", "resource_subtype": null, "created_by": {"gid": "<USER_GID>", '
 '"resource_type": "user"}, "approval_status": null, "assignee_status": null, '
 '"completed": null, "completed_at": null, "completed_by": null, "created_at": '
 'null, "dependencies": null, "dependents": null, "due_at": null, "due_on": '
 'null, "external": null, "html_notes": null, "hearted": null, "hearts": null, '
 '"is_rendered_as_separator": null, "liked": null, "likes": null, '
 '"memberships": null, "modified_at": null, "notes": null, "num_hearts": null, '
 '"num_likes": null, "num_subtasks": null, "start_at": null, "start_on": null, '
 '"actual_time_minutes": null, "assignee": null, "assignee_section": null, '
 '"custom_fields": null, "followers": null, "parent": null, "projects": null, '
 '"tags": null, "workspace": null, "permalink_url": null}}'

OPTION 2:

If you would like a response back with just the fields you requested in opt_fields and the response not mapped to a TaskResponseData object you might want to make an API call using our python-asana v4.X.X call_api method (Example for get a task here). This will return a python dict and to get the double quotes you will need to convert it to a JSON string. Here’s what that looks like all together:


import asana
from asana.rest import ApiException
import json
from pprint import pprint

# Configure OAuth2 access token for authorization: 
configuration = asana.Configuration()
configuration.access_token = "<YOUR_ASANA_PERSONAL_ACCESS_TOKEN>"
api_client = asana.ApiClient(configuration)

try:
    # GET - get a task
    api_response = api_client.call_api(
    "/tasks/{task_gid}",
    "GET",
    path_params={"task_gid": "<YOUR_TASK_GID>"},
    query_params=[('opt_fields', 'created_by,name')],
    header_params={"Accept": "application/json; charset=utf-8"},
    body=None,
    post_params=[],
    files={},
    response_type=object, # If there is an existing response model for the resource you can use that EX: "TaskResponseData" or you can specify one of the following types: float, bool, bytes, str, object
    auth_settings=["oauth2"],
    async_req=None,
    _return_http_data_only=True,
    _preload_content=True,
    _request_timeout=None,
    collection_formats={},
    )
    api_response_json = json.dumps(api_response)
    pprint(api_response_json)
except ApiException as e:
    print("Exception when calling TasksApi->get_task: %s\n" % e)

The result will look like:

'{"data": {"gid": "<TASK_GID>", "created_by": {"gid": "<USER_GID>", "resource_type": "user"}, "name": "task 6"}}'