Search Jira Data
On this page
Introduction
Indexing data from Jira in Algolia is a convenient way to search through content like projects, issues, users, tasks, etc. In this tutorial, you will learn how to quickly import and synchronize Jira objects in Algolia, using Node.js:
- Getting an Atlassian API token
- Fetching all projects from the Jira API
- Indexing them to Algolia
For this, we’ll use the Jira Cloud Rest API v3.
Prerequisites
Familiar with Node.js
This tutorial assumes you are familiar with Node.js, how it works, and how to create and run Node.js scripts. If you want to learn more before going further, we recommend you read the following resources:
Also, you need to install Node.js in your environment.
Have a Jira and Algolia account
For this tutorial, we assume that you:
- already have a Jira account, and want to index your project objects,
- already created an Algolia account. If not, you can create an account.
Install dependencies
You need to connect to your Algolia account. For that, you can use our Algolia Search library. We’ll also install Request to make HTTP calls.
Let’s add these dependencies to your project by running the following command in your terminal:
1
npm install algoliasearch request
Getting an Atlassian API token
To access the Jira Cloud REST API, you need to authenticate each HTTP request you make by including an Atlassian API token. You can create a new API token by following the instructions from Atlassian.
Fetching all projects from JIRA
Now that you have your token, you can make a request to the Jira Cloud REST API Get all projects endpoint.
1
2
3
4
5
6
7
8
9
10
11
12
13
const request = require('request');
const options = {
method: 'GET',
url: 'https://your-domain.atlassian.net/rest/api/3/project',
auth: { username: 'email@example.com', password: 'your-atlassian-token' },
headers: { Accept: 'application/json' }
};
request(options, (err, { statusCode } = {}, body) => {
if (err || statusCode !== 200) throw err;
const projects = JSON.parse(body);
});
Make sure you replace your-domain
with your actual domain, email@example.com
with your username, and your-atlassian-token
with the API Token you generated earlier.
Importing your Jira projects into Algolia
Now that you’ve retrieved your Jira objects, you can create a script to index them into Algolia. You’ll likely want to be able to update and delete the project records later, so you need to specify an objectID
for each of them:
1
2
3
const records = projects.map(project =>
Object.assign({}, project, { objectID: project.id })
);
Now you can index your records
array in Algolia:
1
2
3
4
5
6
7
const algoliasearch = require('algoliasearch');
const client = algoliasearch('YourApplicationID', 'YourAdminAPIKey');
const index = client.initIndex('YourIndexName');
index.saveObjects(records).then(() => {
// done
})
You just indexed your Jira projects into Algolia! You can already search them in your Algolia dashboard. You can also use Algolia’s Search UI Libraries to implement a front-end search experience and make your Jira data searchable anywhere you want.
Keeping Algolia in sync with Jira
Your Jira projects will change over time. For that reason, you may want to periodically fetch the latest data from Jira and update the corresponding records in your Algolia index. Algolia provides several ways to accomplish this.
Atomic reindexing
The first way to keep data in sync is to periodically re-import all records. You can do it by re-running the script from this tutorial (e.g., once a month), thus fetching all your Jira projects
each time, formatting them and uploading them to Algolia. This process would overwrite all existing records in your index.
You need to adapt your existing script to achieve this process. You could add a bit of conditional logic, allowing the user to call the script with a flag to either index data for the first time, or atomically reindex on top of existing data.
For example, you could call your script with an --atomic
flag:
1
node index.js --atomic
You can use the global process.argv
property to access any user input params, and store a boolean to indicate whether your script should index normally or atomically.
1
const atomicFlag = process.argv.slice(2).includes('--atomic');
While much of your original script should remain unchanged, you want to be able to conditionally trigger the atomic reindexing logic (for instance, as a separate function) whenever you pass the --atomic
flag.
1
2
3
const atomicallyReindexData = (client, {indexName}, objects) => {
client.initIndex(indexName).replaceAllObjects(objects);
}
For code hygiene, you can refactor your original indexing block into its own function as well:
1
2
3
4
5
6
const indexData = (index, data) => {
// Index Jira project objects in Algolia
index.saveObjects(records).then(() => {
// done
});
}
Then, you can refactor the request logic of your original script to accommodate your new conditional check.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const start = () => {
// Retrieve Jira projects
request(options, (err, { statusCode } = {}, body) => {
if (err || statusCode !== 200) throw err;
const projects = JSON.parse(body);
// Add object ID property to each project
const records = projects.map(project =>
Object.assign({}, project, { objectID: project.id })
);
// Index or reindex atomically depending on the use of --atomic flag
if (atomicFlag) atomicallyReindexData(client, index, records);
else indexData(index, records);
});
}
This approach is usually the preferred one when you don’t have much data, or when you don’t update it frequently.
Incremental updates
The second way to keep data in sync is to selectively reindex records as the original objects change in Jira. In other words, if you update a Jira project, this would trigger a reindexing of only that record into Algolia. To accomplish this, you can leverage the partialUpdateObjects
method. Jira Webhooks could come in handy to set up such a workflow. To know more, read our incremental updates tutorial.
Batching records
Whatever strategy you pick, we recommend sending records in batches for optimal performances. To learn more about keeping data in sync, read our guides on synchronization.
Putting it all together
Gathering all above steps together, including atomic reindexing, in a single script, you get something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const request = require('request');
const algoliasearch = require('algoliasearch');
const atomicFlag = process.argv.slice(2).includes('--atomic');
const client = algoliasearch('YourApplicationID', 'YourAdminAPIKey');
const index = client.initIndex('YourIndexName');
const options = {
method: 'GET',
url: 'https://your-domain.atlassian.net/rest/api/3/project',
auth: { username: 'email@example.com', password: 'your-atlassian-token' },
headers: { Accept: 'application/json' }
};
const start = () => {
// Retrieve Jira projects
request(options, (err, {statusCode}, body) => {
if (err || statusCode !== 200) throw err;
const projects = JSON.parse(body);
// Add object ID property to each project
const records = projects.map(project =>
Object.assign({}, project, { objectID: project.id })
);
// Index or reindex atomically depending on the use of --atomic flag
if (atomicFlag) atomicallyReindexData(client, index, records);
else indexData(index, records);
});
};
const indexData = (index, data) => {
// Index Jira project objects in Algolia
index.saveObjects(records);
}
const atomicallyReindexData = (client, {indexName}, objects) => {
client.initIndex(indexName).replaceAllObjects(objects);
}
start();
Conclusion
There are many ways to improve and go beyond this example. Here are some ideas:
- Configure relevance settings of your index to improve the ranking/display of search results.
- Index more content sources from Jira, such as issues, users, or tasks.
- Build an InstantSearch search experience to make your Jira content searchable by your teammates.