Last updated Apr 19, 2024

Using pretty URLs in a JIRA plugin

Applicable:

This document applies to JIRA 6.0.

You can use URL structure to add more meaning to your JIRA plugin.  We call this technique pretty urls.

This page discusses the URL routing and decoration modules and shows you how to put plugin instructions in place so you can have control of your URLs and where they lead.

Standard JIRA URL Structures

JIRA generates a number of standard URL structures based on the type of plugin point you use.

For example, webwork actions by default map to a URL like /jira/secure/YourAction.jspa, while plugin servlets map to a URL like /jira/plugins/servlet/yourcode/yourservlet.

With the pretty URL routing modules, you can use a URL structure of your choosing that is more meaningful to your users.

How To Make URLs Pretty

Simple Routing

You can facade any URL into one of your choosing.  You do this by adding <route> elements to your atlassian-plugin.xml

1
2
<routing key="prettyurls-key" path="/prettyurls">
    <route from="/are/{verb}" to="/secure/LessPrettyName.jspa"/>
    <route from="/can/{verb}" to="/secure/LessPrettyName.jspa"/>
</routing>

The first entry above will map urls as shown below:

1
2
http://localhost:2990/jira/prettyurls/are/cool  ==> http://localhost:2990/jira/secure/HorribleName.jspa?verb=cool

One thing to note here is the top level path attribute on the <routing> module declaration.  It is a controlling "prefix" to all routes contained inside.  This prefix is applied for performance reasons.  In order to determine if a URL invocation should be routed at all, the code looks at the top level paths and does a simple cheap string match.  If this is true, then it can proceed with the decidedly more expensive operation of computing the <route> instructions.  This balances the flexibility of having most any pretty url path you like and keeping JIRA as performant as possible.

URL Template Parameters

Pretty URLs use jax-ws syntax to take URL path parameters and make them available to the destination as either further jax-ws variables or more commonly as query parameters.  Any left over parameters that are not remapped into the destination URL are passed as query parameters. For example :

1
2
http://localhost:2990/jira/prettyurls/are/cool?leftover=parameters&are=passedon  ==> http://localhost:2990/jira/secure/HorribleName.jspa?verb=cool&leftover=parameters&are=passedon

You can use the template variables within the destination URL and hence allow more dynamic routing.  For example given :

1
2
<routing key="prettyurls-key" path="/prettyurls">
        <route from="/hello{world}/{id}" to="/plugins/servlet/hello{world}?idParameter={id}"/>
</routing>

you could end up dynamically mapping two different URLs to two differently named servlets, as shown below.

1
2
http://localhost:2990/jira/prettyurls/helloCleveland/key123  ==> http://localhost:2990/jira/plugins/servlet/helloCleveland?idParameter=key123
 
http://localhost:2990/jira/prettyurls/helloSydney/key456  ==> http://localhost:2990/jira/plugins/servlet/helloSydney?idParameter=key123

You can find out more details about the intricacies of jax-ws syntax here

HTTP Verbs

You can limit the HTTP verbs upon which routing will take place via the verbs attribute.  For example:

1
2
<routing key="prettyurls-key" path="/prettyurls">
       <route from="/some/path/you/only/want/on/get" to="/secure/LessPrettyName.jspa" verbs="get"/>
       <route from="/some/path/you/only/want/on/post" to="/secure/LessPrettyName.jspa" verbs="post"/>
       <route from="/some/path/you/only/want/on/postputordelete" to="/secure/LessPrettyName.jspa" verbs="post,put,delete"/>
</routing>

There is also syntactic sugar for the well known HTTP verbs get, put, post, head, delete, options and patch.

1
2
<routing key="prettyurls-key" path="/prettyurls">
        <get from="/some/path/you/only/want/on/get" to="/secure/LessPrettyName.jspa"/>
        <post from="/some/path/you/only/want/on/post" to="/secure/LessPrettyName.jspa"/>
 </routing>

Filter Chain Location

You can control when the routing happens via the location attribute.  The valid values are before-decoration, before-login and before-dispatch.  The most useful location is before-dispatch.

The location meanings are outlined here Servlet Filter Plugin Module

1
2
<routing key="prettyurls-ref-rest-after-encoding" path="/prettyjson" location="before-dispatch">
    <route from="/" to="/rest/prettyjson/1.0/json"/>
</routing>

<routing key="prettyurls-ref-before-login" path="/before/login" location="before-login">
    <route from="/are/{verb}" to="/secure/LessPrettyName.jspa"/>
</routing>

<routing key="prettyurls-ref-before-decoration" path="/before/decoration" location="before-decoration">
    <route from="/get/allowed" to="/secure/LessPrettyName.jspa" verbs="get"/>
    <route from="/get/post/allowed" to="/secure/LessPrettyName.jspa" verbs="get,post"/>
</routing>

Routing REST Requests

If you want to route to REST resources, then you need to change your <rest> module type declarations to ensure they contain the FORWARD dispatcher attribute.  The reason for this is that under the covers, Pretty URLs uses request forwarding as its implementation and as such, the REST resources must be mapped to the FORWARD dispatcher context. The default <rest> dispatcher context is REQUEST only and hence it will never match up as expected without this configuration.

1
2
<rest key="prettyurls-ref-rest" path="/prettyjson" version="1.0">
    <package>com.atlassian.labs.prettyurl</package>
 
    <!--In order to allow REST calls to be intercepted you MUST include a FORWARD call here-->
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</rest>

How To Make Pretty URLs SiteMesh Decorated

JIRA does not SiteMesh decorate all URL paths (and nor should it for a number of reasons including performance) so you have to tell it if you want your new URL paths decorated.  

You can do this via the <sitemesh> module type.

1
2
<sitemesh key="unique-key-for-module-type" path="/pluginpath"/>

This will cause all text/html responses anywhere within that path to be SiteMesh decorated. The matching is done via String.startsWith() semantics.

If you are creating your own pretty URLs, then it's likely you will need to use this module to get decorated like other parts of JIRA.

JIRA comes with a standard set of paths that are SiteMesh decorated.  If your resource is somewhere within any of those paths, you should not give it a <sitemesh> declaration.

PathExcept
/secure/*

/secure/attachment,
/secure/thumbnail,
/secure/applet*

/view/* 
/browse/* 
/plugins/servlet/* 
/issues/* 
/i 
*.jsplegacy - plugins can't and should not supply JSP pages

If a request has the following headers, SiteMesh decoration will not happen:

  • X-SITEMESH-OFF
  • X-PJAX

Rate this page: