Recently I have been building a system for visualizing the relationships and dependencies between issues contained in two separate Jira projects. The data model employs links between entities which are entered using Jira’s issue linking UI within the issue view. However, when extracting the data, I became confused about Jira’s API providing issue link information and I couldn’t find satisfactory information in the reference documentation (REST API documentation and guides in DAC).
After a little research, it seems other developers have also been confused by issue link semantics so I decided to research the topic and create this post in order to reduce further confusion.
Let’s start with an explanation of a simplified version of the model I’ve been building. There are two projects, THING
and FEAT
. The issues in FEAT
represent features, whilst the issues in THING
represent things that we want to build. The features represented by the FEAT
issues may or may not be implemented. Links from THING
issues to FEAT
issues are used to represent the dependencies of the things we want to build. Here’s a fictitious object model (similar to the one I was building) illustrating this:
The projects have the following issue link configuration (obtainable by calling GET /rest/api/2/issueLinkType):
"issueLinkTypes": [{
"id": "10000",
"name": "Blocks",
"inward": "is blocked by",
"outward": "blocks",
"self": "..."
}, {
"id": "10007",
"name": "Depends",
"inward": "is depended on by",
"outward": "depends on",
"self": "..."
}]
Since Jira is being used to capture data and a number of people will be entering information, it’s possible some people will enter dependencies as Depends
links, whilst others will enter them as Blocker
links. However, we’d like the model to treat Depends
and Blocker
links identically.
After creating the four issues represented in the diagram above, the following links were also entered:
- On the
THING-1: Car
issue screen,is blocked by
FEAT-1: Engine
- On the
THING-1: Car
issue screen,depends on
FEAT-2: Wheel
- On the
FEAT-3: Chassis
issue screen,blocks
THING-1: Car
- On the
FEAT-4: Seat
issue screen,is depended on by
THING-1: Car
After entering these links, Jira displays the following in the THING-1: Car
issue screen:
The link information presented by Jira is intuitive and matches my mental model corresponding to the way I entered the link information, noting the different screens the data was entered in and the different link options used.
When the details of THING-1: Car
is retrieved from the REST API using GET /rest/api/2/issue/THING-1
, the issueLinks
field contains the following (where some fields are omitted to keep it brief):
issueLinks: [{
type: {
name: "Blocks",
inward: "is blocked by",
outward: "blocks"
},
inwardIssue: {
key: "FEAT-1"
}
}, {
type: {
name: "Blocks",
inward: "is blocked by",
outward: "blocks"
},
inwardIssue: {
key: "FEAT-3"
}
}, {
type: {
name: "Depends",
inward: "is dependend on by",
outward: "depends on"
},
outwardIssue: {
key: "FEAT-2"
}
}, {
type: {
name: "Depends",
inward: "is dependend on by",
outward: "depends on"
},
outwardIssue: {
key: "FEAT-4"
}
}]
When I saw this at first I was surprised to see some of the issue link data captured within inwardIssue
fields and other issue link data captured within outwardIssue
fields. I was expecting only to see outwardIssue
fields, matching the model illustrated by the first diagram. However, the existence of inwardIssue
fields caused me to interpret it as the following object model:
I was assuming the inwardIssue
and outwardIssue
fields indicated the directionality of the links in my logical model, but that’s not the case. I then started thinking the fields might indicate how the links were added using the Jira UI which is why my scenario included entering links in both THING
and FEAT
issue screens. Taking a closer look at the definitions of the issueLinkTypes
, I then realised the inward and outward fields of the Blocks
issue link type didn’t match my mental model. For example, the Jira UI indicates THING-1: Car
is blocked by
FEAT-1: Engine
, but the issue link data represents the link as an inward link on THING-1: Car
, or in more visual terms, FEAT-1: Engine
→ THING-1: Car
. Whilst Jira issue links are bidirectional, the meaning of each direction is limited to the labels provided in the Jira issue link types configuration. The purpose of the inwardIssue
and outwardIssue
fields is to identify the appropriate label to present to users, which changes depending on which end of a link it is presented in. For example, when the link data returned by the API contains an inwardIssue
field, display the inward
label.
This is why in the THING-1
issue screen, it presents the link to FEAT-1
under the label is blocked by
which makes sense. However, the labels of the Blocks
link type make less sense and is the root cause of why I was surprised to see inwardIssue
fields at THING-1
. It would make more sense if the labels of the Blocks
issue link types were swapped.
"issueLinkTypes": [{
"id": "10000",
"name": "Blocks",
"inward": "is blocked by", < "blocks" makes more sense
"outward": "blocks", < "is blocked by" makes more sense
"self": "..."
}, {
"id": "10007",
"name": "Depends",
"inward": "is depended on by", < makes sense
"outward": "depends on", < makes sense
"self": "..."
}]
In order to map the Jira issue link data to the model I was building, I had to hard code the issue link configuration with an additional field indicating whether to invert the directionality of the links.
issueLinkDirections: [{
id: "10000",
name: "Blocks",
invert: true
}, {
id: "10007",
name: "Depends",
invert: false
}]
This approach is fine when building a system against well known project configurations, but not for a generic product since there is nothing stopping a Jira administrator from updating the issue link configuration. For example, an administrator could swap the inward and outward descriptions of the Blocks
link type. If a generic app needed to be built, it would have to introduce extra project configuration in order to be able to determine the meaning of the issue link directions.
The key lesson I learnt from this investigation is that whilst Jira issue links are bidirectional, the semantics of each direction is only interpretable at the user interface level and not at the API level. For this reason, you should not apply any meaning to field names suggesting directionality such as inward
, outward
, inwardIssue
and outwardIssue
. The purpose of these fields is to facilitate link presentation in user interfaces. The API could alternatively have employed field names such as directionA
, directionB
, directionAIssue
and directionBIssue
.
Up until now, the Jira REST API had documented the inwardIssue
and outwardIssue
fields as follows:
inwardIssue
: The issue the link joins to.outwardIssue
: The issue the link originates from.
As explained above, these descriptions are somewhat misleading so I’ve updated their descriptions as follows:
inwardIssue
: Provides details about the linked issue. If presenting this link in a user interface, use the inward field of the issue link type to label the link.outwardIssue
: Provides details about the linked issue. If presenting this link in a user interface, use the outward field of the issue link type to label the link.
On its own, the above API documentation does not adequately explain the semantics so I have also created a guide to improve the discoverability of key information about Jira’s issue linking model.
Hopefully, this post provides clarity about Jira issue links and in particular, how to interpret issue link data returned by the Jira API.