REST plugin module

This page describes how to use the REST plugin module to expose a REST API from a plugin.

Plugin Framework 2 Only

The REST plugin module described below is available only for OSGi-based plugins using version 2.2 or later of the Atlassian Plugin Framework.

Purpose of the REST Plugin Module

You can use the REST plugin module to expose services and data entities as REST APIs. The Atlassian REST plugin module is bundled with our applications.

REST APIs provide access to resources via URI paths. To use a REST API, your plugin or script will make an HTTP request and parse the response. You can choose JSON or XML for the response format. Your methods will be the standard HTTP methods like GET, PUT, POST and DELETE. Because the REST API is based on open standards, you can use any web development language to access the API.

Mapping the URL to a Resource

A REST resource is exposed at a URL such as this:

1
2
http://myhost.com:port/myapp/rest/api-name/api-version/resource-name

Here's how the parts of the URL are composed and used:

  1. http://myhost.com:port - The operating system directs the request to the application server (e.g. Tomcat) that handles the specified port.

  2. /myapp - Tomcat directs the request to the application myapp.

  3. /rest - The application's web.xml deployment descriptor file maps the URLs to the relevant servlets. So in this case, it maps /rest to our REST servlet, which points to our REST plugin module type.

  4. /api-name/api-version - Now the REST plugin module takes over. The relevant part of the URL (api-name and api-version) are defined as the path and version in the atlassian-plugin.xml file. For example:

    1
    2
    <rest key="helloWorldRest" path="/helloworld" version="1.0">
        <description>Provides hello world services.</description>
    </rest>
    
  5. /resource-name - The final part of the URL mapping (resource-name and sub-elements) is done via annotations on the class, used to declare the URI path, the HTTP method and the media type. Jersey (based on JAX-RS) reads the @Provider and @Path annotations and maps them to classes and methods, so that we know which method is called for each REST resource and method. See the Jersey documentation.

About JAXB Annotations

JAXB converts the Java classes to XML or JSON and vice versa, making use of JAXB annotations. (Available in Java 1.5 and later.)

For example a Java User object with JAXB annotations may look something like this:

1
2
import javax.xml.bind.annotation.*;

@XmlRootElement
public class User
{
    @XmlElement
    private String firstName;

    @XmlElement
    private String lastName;

    // This private constructor isn't used by any code, but JAXB requires any
    // representation class to have a no-args constructor.
    private User() { }

    public User(String firstName, String lastName)
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    ...
}

The XML response content for user John Smith would be:

1
2
<user>
    <firstName>John</firstName>
    <lastName>Smith</lastName>
</user>

By default, on conversion the XML element name will be the same as the object name. Alternatively, you can add the XML element name to the annotation. Something like this: @XmlRootElement(name="principal"). There are specific annotations for arrays, etc. See JAXB's documentation for more details on this.

We have no schema or DTD.

Jersey also handles JSON based on the same JAXB objects as in the example above. The JSON for the example would be:

1
2
{
  "firstName":"John",
  "lastName":"Smith"
}

A trivial REST service class with a single URL returning an instance of User would look like this:

1
2
import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("/")
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public class RestHelloWorldService {
    @GET
    @Path("users")
    public Response getUncompletedUsers() {
        return Response.ok(new User("Fred","Bloggs")).build();
    }
}

Configure the Module in the Plugin Descriptor

The root element for the REST plugin module is rest. It allows the following attributes and child elements for configuration.

Attributes

Name

Description

key

The identifier of the plugin module, i.e. the identifier of the REST module. This key must be unique within the plugin where it is defined. Sometimes you will need to uniquely identify a module. Do this with the complete module key. A module with key fred in a plugin with key com.example.modules will have a complete key of com.example.modules:fred.

Requred.

Default: N/A

path

The path to the REST API exposed by this module. For example, if set to /foo, the REST API will be available at localhost:8080/context/rest/foo/1.0, where 1.0 is the version of the REST API.

Requred.

Default: N/A

version

This is the version of the REST API. This is not the same thing as the plugin version. Different versions of the same API can be provided by different plugins. Version numbers follow the same pattern as OSGi versions, i.e. major.minor.micro.qualifier where major, minor and micro are integers. If version is none, then the REST API will not contain a version number in its URL.

Requred.

Default: N/A

Elements

Name

Description

description

The description of the plugin module, i.e. the description of the REST module. The 'key' attribute can be specified to declare a localisation key for the value instead of text in the element body.

Default: N/A

package

The package from which to start scanning for resources and providers. Can be specified multiple times. Defaults to scanning the whole plugin. Since 2.0

Default: N/A

dispatcher

Determines when the filter is triggered. You can include multiple dispatcher elements.
If this element is present, its content must be one of the following: REQUEST, INCLUDE, FORWARD, ERROR.
Note: This element is only available in Plugin Framework 2.5 and later. In earlier versions of the framework, the filter will be fired on all conditions.

Default: Filter will be triggered on REQUEST only.

Example

Here is an example atlassian-plugin.xml file containing a single public component:

1
2
<atlassian-plugin name="Hello World" key="example.plugin.helloworld" plugins-version="2">
    <plugin-info>
        <description>A basic REST module test</description>
        <vendor name="Atlassian Software Systems" url="http://www.atlassian.com"/>
        <version>1.0</version>
    </plugin-info>

    <rest key="helloWorldRest" path="/helloworld" version="1.0">
        <description>Provides hello world services.</description>
    </rest>
</atlassian-plugin>

Notes on REST API and Plugin Development

JAX-RS and Jersey

Here is some information to be aware of when developing a REST plugin module:

Including the REST Plugin Module into your Project

You can include the REST plugin module as a Maven dependency from our Maven repository.

Developing your REST API as an Atlassian Plugin

To develop a REST API and deploy it into an Atlassian application, you will follow the same process as for any other Jersey application:

  1. Develop your JAX-RS resources, using the annotations @Path, @Provider, etc.
  2. Bundle your resource classes in your plugin JAR file, along with the plugin descriptor atlassian-plugin.xml.
  3. Deploy your plugin to the application.

See Set up the Atlassian Plugin SDK and Build a Project and Configuring the Plugin Descriptor.

Accessing your REST Resources

Your REST resources will be available at this URL:

1
2
http://host:port/context/rest/helloworld/1.0
  • 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.
  • helloworld is the path declared in the REST module type in the plugin descriptor.
  • 1.0 is the API version.

If 1.0 is the latest version of the helloworld API installed, this version will also be available at this URL:

1
2
http://host:port/context/rest/helloworld/latest

How the REST Plugin Module Finds your Providers and Resources

The REST plugin module scans your plugin for classes annotated with the @Provider and @Path annotation. The @Path annotations can be simply declared on a method within a class and do not need to be present at the entity level. 

For those not familiar with the JAX-RS specification, the @Path annotation can be declared at a package, class, or method level.  Furthermore, their effects are cumulative.  For example, if you define this at the package level:

1
2
@Path("/admin")
package myPackage;

then this at the class level:

1
2
package myPackage;

@Path("/myGroup")
public class MyGroup {...};

then this at the method level:

1
2
@Path("/myResource")
public void getResource() {...};

The final URL would be for the helloWorld plugin above:

1
2
http://host:port/context/rest/helloworld/1.0/admin/myGroup/myResource

Notes:

  • The REST plugin module will not scan a library bundled with your plugin, typically bundled in the META-INF/lib directory of the JAR. So make sure you put all providers and resources at the top level in your plugin JAR. 
  • Only one resource method can be bound to the root "/" path.

Easy Way to Request JSON or XML Response Format

When using JAX-RS (and Jersey), the standard way to specify the content type of the response is to use the HTTP Accept header. While this is a good solution, it's not always a convenient one.

The REST plugin module allows you to use an extension to the resource name in the URL when requesting JSON or XML.

For example, let's assume I want to request JSON data for the resource at this address:

1
2
http://host:port/context/rest/helloworld/latest/myresource

I have two options:

  • Option 1: Use the HTTP Accept header set to application/json.

  • **Option 2:**Simply request the resource via this URL:

    1
    2
    http://host:port/context/rest/helloworld/latest/myresource.json
    

If I want content of type application/xml, I will simply change the extension to .xml. Currently the REST plugin module supports only application/json and application/xml.

Working with JSON in Firefox

A handy tool: The JSONView add-on for Firefox allows you to view JSON documents in the browser, with syntax highlighting. Here is a link to the Firefox add-on page.

Differences in JSON and XML rendering of REST responses

By default, JSON responses include any object fields which are explicitly annotated with a JAXB annotation, while XML responses include public fields and fields with public getters.

To get the same behaviour for JSON you need to either annotate each field with @XmlElement or @XmlAttribute, or annotate the class or package with @XmlAccessorType(XmlAccessType.PUBLIC_MEMBER).

References

Developing a REST Service Plugin
Atlassian REST API Design Guidelines version 1
Guidelines for Atlassian REST API Design
Atlassian Plugin Framework Documentation

Rate this page: