Skip to end of metadata
Go to start of metadata

This document provides guidelines to Atlassian developers who are designing REST APIs for Atlassian applications. We are publishing these design principles and guidelines for viewing by the wider community for these 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.
  • If you are developing a plugin that exposes a REST API, you can follow these guidelines to ensure consistency between your plugin and the host application's APIs.
  • We invite and welcome feedback on these design principles.

Document version control

Icon

The design guidelines are under version control. Any significant changes to the 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:

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.

(info) 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:

Use this URI to access the plugin resource with a key of 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:

  • application/json in the HTTP Accept header
  • .json extension

 

XML

Requested via one of the following:

  • application/xml in the HTTP Accept header
  • .xml extension

 

JSONP

Requested via one of the following:

  • application/json in the HTTP Accept header and jsonp-callback query parameter
  • .json extension and jsonp-callback query parameter.

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:

  • self — denotes that the URI points to the entity itself, see Entity ID below.
  • edit — denotes the URI used to update the entity,
  • delete — denotes the URI used to delete the entity,
  • add — denotes the URI used to create the entity.

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:

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:

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:

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:

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:

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:

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:

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.

Cross-site request forgery 

Atlassian uses the XSRF acronym for Cross-site request forgery and not CSRF.

To protect against XSRF attacks:

  1. Ensure that GET requests are idempotent
  2. For rest api classes or methods that will not be used in normal browser 'form' posts
    1. annotate them with @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})

      This protects against xsrf as normal browser form posts cannot contain a content type of MediaType.APPLICATION_XML or MediaType.APPLICATION_JSON.

    2. Alternatively annotate them with @com.atlassian.plugins.rest.common.security.RequiresXsrfCheck. The atlassian-rest-refimpl-plugin has an example of using this annotation.  
  3. For rest api classes or methods that will be used from normal browser 'form' posts
    1. As of atlassian-rest 2.8.0-m9 the com.atlassian.plugins.rest.common.security.RequiresXsrfCheck  annotation can be used to perform xsrf token validation on rest form submissions. This xsrf token 
      validation implementation uses the SAL provided XsrfTokenValidator and  XsrfTokenAccessor interfaces. A plugin which uses this annotation to provide xsrf token validation on a rest method will need to ensure that in all corresponding forms there is a hidden xsrf token parameter with a xsrf token value obtained from the XsrfTokenAccessor interface. For example, the exampleXsrfTokenProtectedMethod method annotated with the RequiresXsrfCheck annotation in the following class

      would have a corresponding form similar to the following

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.

  • GET request returns a representation of the requested entity,
  • The body of other requests will be a Status entity as described in the Status section of this document below.

201

Created

Request created an entity.

  • This cannot happen on GET or DELETE requests.
  • This will happen on POST and may happen on PUT requests.
  • The response should set the Location header to the URI for the created resource.
  • The body of the response is a Status entity as described in the Status section of this document below.

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.

  • The response should set the Location header with the URI to the resource representing the pending action.
  • The body of the response is a Status entity as described in the Status section of this document below.

204

No Content

 

 

301

Moved Permanently

The requested resource has been moved to another location (URI).

  • The response should set the Location header to the URI of the new location of the resource.
  • The body of the response is a Status entity as described in the Status_ section of this document below.

304

Not Modified

The requested resource has not been modified.
The client's cached representation is still valid.

  • No body is allowed for these responses.

401

Unauthorized

Client is not authenticated or does not have sufficient permission to perform this request.

  • The body of the response is a Status entity as described in the Status section of this document below.

404

Not found

No resource was found at this location (URI).

  • The body of the response is a Status entity as described in the Status section of this document below.

412

Precondition Failed

The client specified some preconditions that are not valid.

  • The body of the response is a Status entity as described in the Status section of this document below.

5xx

Server-Side Error

Any server-side error.

  • These codes should not be set programmatically and are reserved for unexpected errors.

Appendix B: Basic Data Types

The link element is used for hyperlinking entities and as entity IDs:

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:

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

Developing a REST Service Plugin
REST Plugin Module
Basics of Exposing REST APIs via Plugins
Welcome to the Atlassian Developer Network

4 Comments

  1. 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 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.

  2. 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 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.

  3. All the discussion above is about XML. There needs to be a similar definition of everything in JSON since the two are not congruent.

  4. Anonymous

    I want to know about Etag support mentioned in this document. Does JIRA REST based API support Etag ? I am not able to see it in the headers while i was trying.