This document provides guidelines to Atlassian developers who are designing REST APIs for Atlassian applications. However, we are publishing these design principles and guidelines for viewing by the wider community, for two reasons:
- If you are a developer/administrator who wants to interact with the REST API in one or more of the Atlassian applications, it will help you to know the principles behind our REST API design.
- We invite and welcome feedback on these design principles.
| Document version control This page is under version control. Any significant changes to these guidelines will undergo review and approval and will be published under a new version number, as reflected in the page title. |
On this page:
Background to Atlassian REST APIs
Atlassian is currently working towards creating standardised REST APIs across all of our applications. Some of our applications already provide REST APIs, and some applications are providing new REST APIs or updating their existing APIs in an upcoming release. (Date of writing this paragraph: April 2009.)
Each application (Confluence, JIRA, Crowd, etc) will provide its own REST APIs, exposing the application-specific functionality. The goal is for these application-specific APIs to share common design standards, as described on this page.
For details of each application's APIs, please refer to the development hub in the documentation for the application concerned.
Goal of these Guidelines
These guidelines are for Atlassian developers who are designing REST APIs for Atlassian applications. The goal is to keep REST API implementations as consistent as possible. These guidelines apply to all REST APIs, including:
- REST APIs that use Atlassian's Jersey-based REST plugin module type.
- Other REST APIs not based on the plugin.
Using these Guidelines
Following or Moving Away from the Guidelines
These guidelines provide one way of doing things that might not always be the only way nor the best way. If you think that is the case, feel free to move away from the guidelines. You should be aware of potential repercussions such as security issues, consistency issues, etc.
We strongly recommend that someone who is familiar with these guidelines should review your REST API code.
Examples used in the Guidelines
The examples used in these guidelines assume that we have a REST API supplied by an Atlassian plugin called the 'Unified Plugin Manager' plugin, 'UPM' or 'upm'. (This is a real plugin that is currently under development.) The UPM allows you to discover and manage the plugins installed on an Atlassian application.
REST Resources
URIs for Resources
URI Structure
Given a list of foo entities, the following URI scheme provides access to the list of foo entities and to a particular foo:
| URI | Method | Notes |
|---|---|---|
| /foo | GET | This returns a list of the foo items. By default items in the list are a minimal representation of a foo entity. Note that we use the singular for the directory name. |
| /foo/{key} | GET | This returns the full content of the foo identified by the given key. |
Sub-elements of a foo entity are made available as sub-resources of /foo/{key}.
Examples
For our example, let's take a plugin resource within the 'upm' REST API.
Use this URI to access a list of plugins:
http://host:port/context/rest/upm/1/plugin
Use this URI to access the plugin resource with a key of a-plugin-key:
http://host:port/context/rest/upm/1/plugin/a-plugin-key
Structure of the above URI:
- host and port define the host and port where the application lives.
- context is the servlet context of the application. For example, for Confluence this would typically be confluence.
- rest denotes the REST API.
- upm is the path declared in the REST module type in the plugin descriptor.
- 1 is the API version. See the section on API version control below.
Standard Query Parameters in URIs
Below is a list of standard query parameters. These names are reserved in our REST APIs and should be used according to the notes in the table below.
| Query Parameter | Notes |
|---|---|
| expand | Used for title expansion. See section on title expansion below. |
| start-index | An integer specifying the starting point when paging through a list of entities. Defaults to 0. |
| max-results | The maximum number of results when paging through a list of entities. No default is provided. We recommend that APIs should define their own default. Applications should also define a hard limit on the number of items that can be requested at the same time. |
| jsonp-callback | Used to define the name of the JavaScript function to be used as the JSONP callback. |
Entities
Representations (Content Types) of Entities
By default, REST APIs must support multiple content types.
| Representation | Requested via... | Notes |
|---|---|---|
| JSON | Requested via one of the following:
|
|
| XML | Requested via one of the following:
|
|
| JSONP | Requested via one of the following:
|
Only available on GET. The returned content type MUST be application/javascript. |
Hypertext Linking within an Entity
Entities can have links to each other. This is represented by the <link> tag. The <link> tag supports the following attributes:
| Attribute | Description |
|---|---|
| href | The URI of the entity linked to. |
| rel | The relationship between the containing entity and the entity linked to. Examples of possible values:
|
| title | Optional. A short description of the entity linked to. |
Links to the URI that will perform operations on an entity have their rel attribute set to edit, delete or add. We recommend that entities provide these links as part of their content.
Links should follow some simple rules:
- Links use the same base URL independently of server-side implementation. So, if the REST API is available at http://host:port/context/rest/api/, then links to other resources should use this as their base URL.
- Whenever the user specifies an extension, such as .xml, .json, etc, links should have this same extension as far as possible.
- Links do not have query parameters.
Example
The following plugin entity has a <link> tag with a rel attribute identifying the entity's own ID via a URI pointing to itself:
<plugin key="a-plugin-key" enabled="true" expand="modules,info"> <link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key" /> <info name="A plugin"/> <modules size="2" expand="module"/> </plugin>
Entity ID
Every addressable entity should have a <link> tag with the attribute rel="self" pointing to its own URI. See the section on linking above.
Version Control for Entities
Entities SHOULD be served with an ETag header.
Read-only entities and lists of entities may be served without an ETag header. Providing an ETag header for these resources will help with caches and conditional requests, but the header need not be included if calculating the ETag is too expensive or difficult.
The ETag for a resource MUST be the same regardless of the requested representation or title expansion state.
The server MUST treat If-Match and If-None-Match headers provided by clients as defined in RFC 2616.
PUT or DELETE API requests SHOULD provide an If-Match header, and SHOULD react meaningfully to 412 (Precondition Failed) responses.
Collections of Entities
Collections of entities should define the following attributes:
| Attribute | Description |
|---|---|
| size | The total size of items available in the collection. This can be different from the actual number of items currently listed in the collection if the start-index and max-result query parameters have been used. |
| start-index | If used to filter the collection elements. |
| max-result | If used to filter the collection elements. |
Example
In the response below, the <modules> entity has a size attribute indicating that there are 2 plugin modules in the collection:
<plugin key="a-plugin-key" enabled="true" expand="modules,info"> <link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key" /> <info name="A plugin"/> <modules size="2" expand="module"/> </plugin>
Title Expansion for Entities
In order to be minimise network traffic and simplify some APIs from the client perspective, we recommend that APIs provide title expansion. This works by using the expand query parameter and setting its value to the last path element of the entity's schema.
The expand query parameter allows a comma-separated list of identifiers to expand. For example, the value modules,info requests the expansion of entities for which the expand identifier is modules and info.
You can use the dot notation to specify expansion of entities within another entity. For example modules.module would expand the plugin entity (because its expand identifier is modules) and the module entities within the plugin. See example 4 below.
Expandable entities should be declared by parent entities in the form of an expand attribute. In example 1, the plugin entity declares modules and info as being expandable. The attribute should not be confused with the query parameter which specifies which entities are expanded.
Example 1. Accessing a Resource without Title Expansion
For our example, let's take a plugin resource within the 'upm' REST API.
Use this URI to access the plugin resource without specifying title expansion:
http://host:port/context/rest/upm/1/plugin/a-plugin-key
The response will contain:
<plugin key="a-plugin-key" enabled="true" expand="modules,info"> <link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key" /> <info name="A plugin"/> <modules size="2" expand="module"/> </plugin>
Example 2. Expanding the info Element
Use the following URI to expand the info element in our plugin resource:
http://host:port/context/rest/upm/1/plugin/a-plugin-key?expand=info.
Now the response will contain:
<plugin key="a-plugin-key" enabled="true" expand="modules,info">
<link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key" />
<info name="A plugin">
<description>This is an awesome plugin</description>
<version>1.1</version>
</info>
<modules size="2" expand="module"/>
</plugin>
Example 3. Expanding the Collection of Modules
Use this URI to expand the module collection in our plugin resource:
http://host:port/context/rest/upm/1/plugin/a-plugin-key?expand=modules
The response will contain:
<plugin key="a-plugin-key" enabled="true" expand="modules,info">
<link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key" />
<info name="A plugin"/>
<modules size="2" expand="module">
<module key="module-key-1">
<link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key/module/module-key-1" />
</module>
<module key="module-key-2">
<link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key/module/module-key-2" />
</module>
</modules>
</plugin>
Note that the above URI does not expand each individual module.
Example 4: Using the Dot Notation to Expand Entities within another Entity
Use the following URI to expand the modules inside the collection within our plugin resource:
http://host:port/context/rest/upm/1/plugin/a-plugin-key?expand=modules.module
The response will contain:
<plugin key="a-plugin-key" enabled="true" expand="modules,info">
<link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key" />
<info name="A plugin"/>
<modules size="2" expand="module">
<module key="module-key-1">
<link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key/module/module-key-1" />
<name>Module 1</name>
<description>This is my first module</description>
</module>
<module key="module-key-2">
<link rel="self" href="http://host:port/context/rest/upm/1/plugin/a-plugin-key/module/module-key-2" />
<name>Module 2</name>
<description>This is my second module</description>
</module>
</modules>
</plugin>
Using Index Values to Expand a Collection
You can also set indices to expand a given set of items in the collection. The index is 0 based:
- modules[3] will expand only the module at index 3 of the collection.
- modules[1:3] will expand modules ranging from index 1 to 3 (included). Note that [:3] and [3:] notations also work and the range goes respectively from the beginning of the collection and to the end of the collection.
- modules[-1] will expand the last module. Other negative index values also work and indices are counted from the end of the collection.
Version Control for APIs
APIs must be subject to version control. The version number of an API appears in its URI. For example, use this URI structure to request version 1 of the 'upm' API:
http://host:port/context/rest/upm/1/...
When an API has multiple versions, we recommend:
- Two versions should be supported at the same time.
- If two or more versions are available, applications may provide a shortcut to the latest version using the latest key-word.
For example, if versions 1 and 2 of the 'upm' API are available, the following two URIs would point to the same resources:
When to Change the Version
A version number indicates a certain level of backwards-compatibility the client can expect, and as such, extra care should be taken to maintain this trust. The following lists which types of changes necessitate a new version and which don't:
Changes That Don't Require a New Version
- New resources
- New HTTP methods on existing resources
- New data formats
- New attributes or elements on existing data types
Change That Require a New Version
- Removed or renamed URIs
- Different data returned for same URI
- Removal of support for HTTP methods on existing URIs
Security
Authentication
Every REST API MUST at least accept basic authentication.
Other authentication options are optional, such as Trusted Apps, OS username and password as query parameters, or 'remember me' cookies.
By default, access to all resources (using any method) requires the client to be authenticated. Resources that should be available anonymously MUST be marked as such. The default implementation SHOULD use the AnonymousAllowed annotation.
Authorisation
Authorisation is NOT handled by the REST APIs themselves. It is the responsibility of the service layer to make sure the authenticated client (user) has the correct permissions to access the given resource.
XSRF
To prevent XSRF attacks, REST APIs MUST NOT accept POST requests with the application/x-www-form-urlencoded content type. We accept multipart/form-data content type as long as you use only file parameters. To POST, PUT requests with files and other parameters you SHOULD use the multipart/mixed content type.
The XSRF attack vector is the web browser. As long as GET requests are idempotent, only POST operations can be exploited for XSRF attacks. However, these are restricted by the web browser to content types application/x-www-form-urlencoded and multipart/form-data. Therefore, by refusing POST requests that use application/x-www-form-urlencoded or multipart/form-data, we prevent XSRF attacks throughout our REST APIs.
Exception: When using the REST APIs to serve normal pages you will have to enable POST with application/x-www-form-urlencoded. In that case you should put in place some protection against XSRF such as using a form token that is valid for only one POST request.
Caching
REST APIs SHOULD support conditional GET requests. This will allow the client to cache resource representations. For conditional GET requests to work, the client MUST send the ETag value when requesting resources using the If-None-Match request header. The ETag is the one provided by a previous request to that same URI. See the section on version control for entities below.
Server implementations should acknowledge the If-None-Match header and check whether the response should be a 304 (Not Modified). See the section on response codes below.
Concurrency
PUT or DELETE API requests SHOULD provide an If-Match header, and SHOULD react meaningfully to 412 (Precondition Failed) responses. See the section on response codes below.
The ETag is the one provided by a previous GET request to that same URI. See the section on version control for entities below.
Not Yet Covered in these Guidelines
Some items worth discussing in the guidelines are currently out of scope:
- Common entities
- Batching
- Gzip
- OpenSearch
- Internationalisation (i18n)
Appendix A: Response Codes
This list shows the common HTTP response codes and some brief guidelines on how to use them. For the complete list of HTTP response codes, please refer to section 6 of RFC 2616.
| Code |
Name |
Description |
Notes |
|---|---|---|---|
| 200 |
OK |
Request was processed as expected. |
|
| 201 |
Created |
Request created an entity. |
|
| 202 |
Accepted |
The request has been acknowledged but cannot be processed in real time. For example, the request may have scheduled a job on the server. |
|
| 204 |
No Content |
||
| 301 |
Moved Permanently |
The requested resource has been moved to another location (URI). |
|
| 304 |
Not Modified |
The requested resource has not been modified. The client's cached representation is still valid. |
|
| 401 |
Unauthorized |
Client is not authenticated or does not have sufficient permission to perform this request. |
|
| 404 |
Not found |
No resource was found at this location (URI). |
|
| 412 |
Precondition Failed |
The client specified some preconditions that are not valid. |
|
| 5xx |
Server-Side Error |
Any server-side error. |
|
Appendix B: Basic Data Types
Link
The link element is used for hyperlinking entities and as entity IDs:
<link title="This is my resource" rel="edit" href="http://host:port/context/rest/api/1/myresource" />
See the sections on linking and entity IDs above.
Status
Any request which produces a status code with no body will have a body formatted like this:
<status>
<plugin key="a-plugin-key" version="1.0" />
<status-code>201</status-code>
<sub-code>604</sub-code>
<message>Some human readable message</message>
<etag>233223</etag>
<resources-created>
<link rel="self" href="http:..." />
</resources-created>
<resources-updated />
</status>
| Element | Description |
|---|---|
| plugin | Describes the plugin which provides the REST API. This element is present only if the REST API is provided by a plugin. |
| status-code | The actual HTTP code of the response. See the section on response codes above. |
| sub-code | Another code that defines the error more specifically. It is up to REST API developers to define their various codes. |
| resources-created | This element is present when resources have been created. It consists of link elements to the created resources. |
| resources-updated | This element is present when resources have been updated. It consists of link elements to the updated resources. |
RELATED TOPICS
Plugin Tutorial - Writing REST services
Glossary - Terms and Definitions
REST Plugin Module Type
Overview of REST Implementation using the REST Plugin Module Type
Welcome to the Atlassian Developer Network





Comments (2)
Apr 29, 2009
Matt Doar says:
Looking good. I'm most familiar with SOAP and JIRA, so please read this followin...Looking good. I'm most familiar with SOAP and JIRA, so please read this following with that context. A few pieces of feedback:
1. How about using v1 instead of 1 in the URL for the version number? It's a bit more obvious what it is rather than just a number. "latest" and the slicing syntax [1:3] are nice touches.
2. The ability to retrieve JSON or XML is excellent. I'm looking forward to that.
3. Users will want to be able to avoid using ids for metadata as far as possible. For example, using "change this issue to the status Foo" rather than "change this issue to status 10001"
4. Performance issues when uploading sizeable data such as attachments is important. SOAP is particularly slow in this case.
5. Should be able to handle Apache frontends that redirect http://jira.example.com to http://www.example.com/jira:8080 for example. This may just be a matter of documentation.
6. Needs to handle https as well.
In general, I feel that administrative plugins are as important as being able to access the data. Those actions always seemed to receive a lower priority in the SOAP API and lead to numerous complaints.
Apr 30, 2009
Samuel Le Berrigaud says:
To reply to all your points: 1. Using v1 might be more obvious. I think for the...To reply to all your points:
1. Using v1 might be more obvious. I think for the time being we will stick with just the version number. Nothing prevent us from adding support for both as the REST Plugin Module Type takes care of that.
2. Thanks, JAX-RS and Jersey make that easy.
3. I agree with you. I actually think we should support both when we can. I don't want to put it in the guidelines right now but it certainly something that RESTful API developers will have to think about.
4. Uploads should be as fast as the application allows. REST should not be the limiting factor; we're using the standard HTTP file transfer mechanisms. Application-specific performance issues are outside the scope of these guidelines.
5. This will work the same way as it does for any web page currently. Mentioning it in the document might be a good idea.
6. Same as for point 5.
Almost every part of the applications deserves a REST API. As always it is a matter of time/priority. The good thing is that anyone can developer RESTful API for our product as plugins. So if/when there is something that you wish were there, you can just make it happen.
Thanks for your feedback.