ITKarma picture

Nowadays, few web services or applications do without functionality where users can complain (notify, register) about various types of content, be it a grammatical error in the text, erroneous language, uninteresting or not informative content (as an exercise, lesson, article, training material or part of the functionality) . The ability to “report a problem” is an integral part of involving users in the product, implementing one of the forms of collecting feedback and the ability to improve your application as a whole.

All user complaints must be stored somewhere, be prioritized, conveniently tracked, and, moreover, must be processed on time. But it is not always possible to allocate enough resources for the development and maintenance of such a system, because there will always be a task in the backlog with a higher priority. Below I will tell you how we quite effectively and quickly solved this problem in Uxcel using the JIRA REST API.

Why do we need “Report a problem”?

Add a little context - why do we provide complaints functionality and what do we need?
Uxcel is a web service for learning UI/UX in a playful way. Our training element is “Practice” - in most cases these are 2 images where one is true and the other is not. That allows you to train the eye to find defects even in visually identical elements. Each practice , in addition to images, has a hint (hint - hint for the correct answer) and a description (description) with a theory regarding this task.

ITKarma picture

Since the number of practices is in the thousands - this means that somewhere there may be a grammatical error, and somewhere the picture, clue or theory is not clear to the user, so it’s very important to take into account everyone’s opinion in order to maintain reference content. For all these cases, you need to give the opportunity “Report a problem” directly during the passage of practices , without interrupting the process, as quickly and conveniently as possible. Moderators, however, need to be able to view a list of practices with complaints, filter, find the most popular problematic ones, monitor the current status and close complaints, keeping a history.

ITKarma picture

In order not to reinvent the wheel with its own boards, tickets and backlog, as well as to store all the tasks of the teams in one system and even in common sprints, it was decided to use the JIRA + REST API for these purposes.

Organization of tickets in JIRA

For each practice that has at least 1 complaint, a BUG is created in JIRA in the highlighted Practices Reports epic. And the complaints themselves are stored in the form of comments on relevant bugs- practices . In addition to this, Label (in our case such as: Course, Gym, UEye) is added for different types of practices. The general logic is presented in the diagram below:

ITKarma picture

Thus, the content team selects the most priority practices (in the form of bugs) for correction in each sprint.

Now let's take a look at the technical details of the implementation.

Integration with the JIRA REST API

The first thing you need to do is create a token API in JIRA in order to access the JIRA API. For use on production, I recommend creating a separate user on whose behalf tickets will be created, otherwise you will have to fend off constant notifications, while for an individual user it’s easier to turn them off right away.

Getting the Token API:

ITKarma picture

  • Set the token name - > click Create

ITKarma picture

Done. We save the created token somewhere, you can not lose it.

Now you can make API requests to JIRA. Each request is sent a header containing the email (the user for whom the token was created) and the token itself - we pass them through the implementation of HTTP basic authentication .

Example code (all TypeScript code for NodeJS) :

private generateAuthHeader(): string {//конвертируем строку email:apiToken в Base64 const basicAuthValue=Buffer.from(`${this.jiraEmail}:${this.jiraApiToken}`).toString('base64'); return `Basic ${basicAuthValue}`; } 

Note: we use AWS Secrets Manager to store keys and passwords. It is not safe to store such data directly in the code. More information here .

Creating a bug through the API

There is very little preparation left. In order to create a bug, we need to know its Issue ID in JIRA. One way to find out is to invoke a GET request for information about all types:

GET https://{id} 

Since this is a one-time operation, you can use Postman to avoid writing code:

ITKarma picture

In the Authorization tab, select Type: Basic Auth , enter email and api token.

In the answer we are interested in this part:

{ "self": "https://{id}", "id": "10001", "description": "A problem or error.", "iconUrl": "https://${id}", "name": "Bug", "untranslatedName": "Bug", "subtask": false, "avatarId": 10303 } 

After we recognize the Issue Id of type BUG (“10001”) we need to find out the Project Id to which the bug will belong. Similarly, we can get a list of all the projects and find the id of the desired one.

To do this, make a GET request to

GET https://{id} 

And the last preparatory step: as I mentioned above, we store bugs in a separate epic (Jira Epic). You do not need to know its id, just copy its Key (located before the epic name, or in the address bar, for example UX-1) .

Everything is ready to create the first bug through the API.

I used the npm package Got to create HTTP requests for NodeJS.

await{ url: `${this.jiraApiHost}/issue`,//jiraApiHost=https://{id} headers: { Authorization: authorization,//созданный Basic Auth Header в методе generateAuthHeader 'Content-Type': 'application/json' }, responseType: 'json', json: { update: {}, fields: { issuetype: { id: this.jiraBugTypeId },//полученный id типа BUG (пример - ‘10001’) project: { id: this.jiraPracticeReportProjectId },//id проекта (пример - ‘10005’) parent: { key: this.jiraPracticeReportEpicKey },//ключ Epic (пример - UX-1) summary: practiceTicketName,//имя практики формата - [practiceId] practiceName (#reports) labels: [practice.label] } } }); 

API Reference

A bug has been created. Next, we consider the remaining methods necessary to configure the full cycle of complaints handling and maintaining them in JIRA, such as: Search, Status update, Information update, Adding a comment to the bug.

Search for a bug through the API

A bug search is the initial operation in the user complaint API. You need to make sure that there is no ticket for the appealed practice , only in this case we create it.

Sample code:

//формируем JQL запрос, ищем по типу BUG в эпике где хранятся жалобы по id практики (которое есть в названии каждого бага) const jql=`issuetype=Bug AND project=CNT AND parent=${this.jiraEpicKey} AND text ~ "${practiceId}" order by created DESC`; const response=await got.get({ url: `${this.jiraApiHost}/search?jql=${jql}`, headers: { Authorization: authorization }, responseType: 'json' }); const practiceJiraTicket=response.body['issues'] && response.body['issues'][0]; 

API Reference

If a bug is found for practice , you need to update its status if the problem has been resolved and the bug was in CLOSED status.

Updating the status of a bug through the API

To update the status, we will use Transitions. But for this you need to find out the Status ID for the TODO/OPENED status (the status depends on the JIRA settings).

Back to Postman:

GET https://{id}{projectIdOrKey}/statuses 

By the project id we get all the statuses, find the status that indicates the open state of the ticket and save its id.

Request to transfer the bug to open status:

await{ url: `${this.jiraApiHost}/issue/${practiceJiraTicket.key}/transitions`,//где practiceJiraTicket - найденный объект бага headers: { Authorization: authorization, 'Content-Type': 'application/json' }, responseType: 'json', json: { transition: { id: this.jiraToDoStatusId//id статуса полученного выше (пример - ‘10006’) } } }); 

API Reference

The next step after translating the found bug into the open state is updating the name (and, if necessary, the description or priority).

Updating the name of the bug through the API

The names of the bugs should reflect the current state of the problem, in addition to the id and the name practice in the name of the bug statistics can be stored for more convenient search and viewing of open complaints on the board. Statistics in our case means the number of complaints about this practice and the percentage of correct answers. So, if in practice the number of correct answers is rather low or the number of complaints is more than n - you can increase the priority.

API call code to update the bug:

await got.put({ url: `${this.jiraApiHost}/issue/${practiceJiraTicket.key}`, headers: { Authorization: authorization, 'Content-Type': 'application/json' }, responseType: 'json', json: { update: { summary: [{ set: newPracticeTicketName }] } } }); 

API Reference

Next, we add the details of the complaint itself in the form of a comment on an already prepared bug.

Adding a comment through the API

Each user complaint is stored as a comment on the bug- practice .

Comment creation code:

await{ url: `${this.jiraApiHost}/issue/${practiceJiraTicket.key}/comment`, headers: { Authorization: authorization, 'Content-Type': 'application/json' }, responseType: 'json', json: comment//подробности о формировании объекта ниже }); 

API Reference

The comment object is formed as Atlassian Document Format .
The site also has a Builder , which greatly simplifies the generation of the object : just format the text to fit your needs in the editor - at the same time the resulting JSON object is created in parallel.

Done! Now you can accept, store, process, throw in sprints and conveniently search for user complaints using JIRA.

How we have complaints in the form of comments:

ITKarma picture

The final view of our list of bugs in JIRA (the name contains id, #N - number of complaints,% - correct answers) :

ITKarma picture

Then everything depends on your imagination and requirements. For example, you can:

  • implement asynchronous processing of complaints so that the user does not wait until the entire chain of requests to JIRA passes (we have implemented AWS SNS)
  • add a priority field for bugs and change the priority depending on the number of complaints for more convenient filtering in the board
  • additionally inform moderators in Slack when a new complaint appears with a link to the created bug ( slack/webhook package - very easy to integrate)
  • configure JIRA Webhooks to automatically notify all users when closing a bug who complained about the practice with gratitude for participating in the improvement of the product
  • automatically assign a bug to the author of the content for which the complaint has been received.

Thank you all for your attention! I hope the article was useful to you :)
I will be happy to answer your questions!