If you're anything like me, you enjoy pushing boundaries—testing things just to see if they break or lead to something unexpected. But let’s get to the real reason I’m writing this article. If you manage Jira or work with API's in your organization, you’ve probably noticed changes in the Jira Issue Search API.
Now, if you’ve been keeping up with Atlassian’s developer changelogs, this won’t be news. But regardless of whether you were following or not, the bottom line is: the API is changing, and that means some things will break. I’m talking about those scripts, automations, or little tools you wrote ages ago and forgot about, which quietly keep your systems running.
While this change might cause some headaches, it’s not all bad news. In fact, the old API had its issues. It pulled large amounts of data with little control, forcing you to parse unnecessary information. The new API, on the other hand, lets you request only the fields you need. This makes responses smaller, faster, and easier on memory.
However, not everything is smooth sailing. For instance, the startAt
parameter is gone. It’s been replaced by nextPageToken
, which actually improves performance—but it does mean rewriting parts of your code.
As someone who builds and maintains automation around Jira, I’ve already adapted to this with my Python library, jiraone. If you’ve seen my previous posts, you’ll know this library supports tasks like exporting issues, getting changelogs, calculating time-in-status, and more—all of which used the old issue search API.
With version v0.8.7,
I introduced support for the new API, making it easier for admins and developers to transition without losing much functionality.
Here's how you can use the new API with jiraone
. See the docs for more information about the arguments you can use.
# previous import statement
resp = LOGIN.get(endpoint.search_cloud_issues(
query='project = AT',
fields=None,)
)
if resp.status_code < 300:
data = resp.json()
print(data)
# {["issues": [...]]}
The reason I used fields=None is that I don't want to return all field data. You can specify what field you want returned by typing a string of the field name separated by a comma. If the argument is removed, by default, all fields are returned, which will be a large payload to parse. The query argument expects any valid JQL and requires a bounded query, which means you have to specify exact search restrictions; otherwise, it won't work.
Example: POST Request (for larger queries)
# previous import statement
resp = LOGIN.post(endpoint.search_cloud_issues(
query='project = AT',
method="post",
fields=None,
), payload=endpoint.get_issue_search_payload)
if resp.status_code < 300:
data = resp.json()
print(data)
# {["issues": [...]]}
Notice that you don’t need to create a payload, but what happens here is that by defining the arguments you want, it is automatically added as an object when you call endpoint.get_issue_search_payload
and assign it as a value to the payload argument of LOGIN.post
To handle pagination (since results may span multiple pages), you need to loop using the nextPageToken:
# previous expressions
if resp.status_code < 300:
data = resp.json()
while "nextPageToken" in data:
if "issues" in data:
# the issues will be a list which you can loop
issues = data.get("issues")
# you can attach the issues data to another object
# or process it the way you see fit
resp = LOGIN.get(endpoint.search_cloud_issues(
query='project = AT',
fields=None,
next_page=data.get("nextPageToken")
))
if resp.status_code < 300:
data = resp.json()
enhance_search
To simplify pagination, I added the enhance_search function in the jiraone.utils module. It automatically handles paging and returns all results with a total count of how many issues it's returning. For those of you thinking of making multiple APIs, this handles that request quite nicely.
# previous import statement
from jiraone.utils import enhance_search
data = enhance_search(endpoint.search_cloud_issues(
query='project = AT', fields=None,
) )
print(data)
# {["total": 287, "issues": [...]]}
# previous import statement
from jiraone.utils import enhance_search
data = enhance_search(endpoint.search_cloud_issues(
query='project = AT',
method="post",
fields=None,),
method="post" )
print(data)
# {["total": 287, "issues": [...]]}
Note: Both
search_cloud_issues
andenhance_search
take amethod
argument. If using POST, you must set"post"
in both places.
Here’s a quick example using a config file and script: config.json
{ "user": "myuser@example.com",
"password": "MY_API_TOKEN",
"url": "https://yoursite.atlassian.net"
}
Python file, e.g. myscript.py
from jiraone import endpoint, LOGIN
from jiraone.utils import enhance_search
import json
file = "config.json"
config = json.load(open(file))
LOGIN(**config)
data = enhance_search(endpoint.search_cloud_issues(
query='project = AT',
method="post",
fields=None,
), method="post"
)
print(data)
# {["total": 287, "issues": [...]]}
If you’re using Jira DC, you can continue using the older endpoint.search_issues_jql
.
This change may be disruptive in the short term, but it opens the door to more efficient, flexible scripting. Hopefully, this article helps you adapt your tools and keep your Jira automations running smoothly.
Prince Nyeche
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
2 comments