Representational State Transfer (REST) endpoint is a URL that runs a script. REST endpoints are configured programmatically. You can define REST endpoints in ScriptRunner, for example, to:

Adding a REST Endpoint

Follow this task to create a custom REST endpoint:

  1. Select the Cog icon, and then select General Configuration.

  2. Scroll to the ScriptRunner section in the left-hand navigation, and then select REST Endpoints.

  3. Select Add a New Item, and the select the Custom endpoint

Use the following REST endpoint example to examine the different parts of the script:

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonBuilder
import groovy.transform.BaseScript

import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response

@BaseScript CustomEndpointDelegate delegate (1)

doSomething( (2)
    // bitbucket-administrators is a group we have added ourselves
    httpMethod: "GET", groups: ["bitbucket-administrators"] (3)
) { MultivaluedMap queryParams, String body -> (4)
    return Response.ok(new JsonBuilder([abc: 42]).toString()).build() (5)
}
1 This line makes methods in your script recognisable as endpoints, which is required.
2 The name of the REST endpoint, which forms part of the URL. In this example, it is doSomething.
3 This line configures the endpoint, which HTTP verb to handle, and what groups to allow.
4 This line contains parameters that are provided to your method body.
5 The body of your method, where you will return a javax.ws.rs.core.Response object.

You can add this REST endpoint to the list of configured endpoints as an inline script or by copying into a file and adding that file as a script file. To test this endpoint, type this text into your browser:

Notice the last part of the text is the name doSomething.
<bitbucket_base_url>/rest/scriptrunner/latest/custom/doSomething

You could also type this into the command line utility:

  • Again, notice the name doSomething in each command.

  • admin:admin corresponds to a username and password.

>curl -u admin:admin http://localhost:8080/bitbucket/rest/scriptrunner/latest/custom/doSomething
{"abc":42}

If you are using a file, you can change the response. Uou may need to select the Scan button on the REST Endpoints page before calls to the endpoint return the new response. See the section on Script Root Scanning below.

Configuration

The general format of a method defining a REST endpoint is:

methodName (Map configuration, Closure closure)

For the configuration, only the following options are supported:

httpMethod Choose one of: * GET * POST * PUT * DELETE

groups

One or more groups. If the requesting user is in any of the groups, the request is allowed.

Either or both of these can be omitted. If you omit the groups attribute, the endpoint will be available to unauthenticated users.

Use these parameters for the closure:

MultivaluedMap queryParams

This corresponds to the URL parameters.

String content

This is the body of the request for httpMethod (Post, Put, etc.).

HttpServletRequest request

The request object; you can use this to get the requesting user for instance.

You can use any of these forms for your closure:

something() { MultivaluedMap queryParams ->
something() { MultivaluedMap queryParams, String body ->
something() { MultivaluedMap queryParams, String body, HttpServletRequest request ->

What the closure contains depends on what you need access to.

Access request URL

Sometimes you may need to use the URL path after your method name, for instance in the following call, you want to retrieve the /foo/bar:

<base_url>/rest/scriptrunner/latest/custom/doSomething/foo/bar

To get this, use the 3-param form of the closure definition, and call the getAdditionalPath method from the base class:

doSomething() { MultivaluedMap queryParams, String body, HttpServletRequest request ->

    def extraPath = getAdditionalPath(request)
    // extraPath will contain /foo/bar when called as above
}
In previous versions, an extraPath variable was injected into the scripts, but this is not thread-safe - use the above method instead.

Examples

Allow Cross-Domain Requests

This example demonstrates how to access the official REST API from another domain. As at the time of writing Bitbucket does not support CORS (cross-origin requests).

To demonstrate this when trying to GET from the following REST endpoint from http://some.domain.com

<bitbucket_base_url>/rest/api/1.0/projects/PROJECTKEY/repos/reposlug

You may have received an error like

Origin http://some.domain.com is not allowed by Access-Control-Allow-Origin.
@BaseScript CustomEndpointDelegate delegate

// replace this url with your Bitbucket instance url
def http = new RESTClient("https://bitbucket.instance.com")

// add authentication to proxy request
http.client.addRequestInterceptor(new HttpRequestInterceptor() {

    void process(HttpRequest httpRequest, HttpContext httpContext) {
        httpRequest.addHeader('Authorization', 'Basic ' + 'username:password'.bytes.encodeBase64().toString())
        httpRequest.addHeader('X-Atlassian-Token', "no-check")
    }
})

bitbucketproxy(
    httpMethod: "GET", groups: ["bitbucket-administrators"]
) { MultivaluedMap queryParams, String body, HttpServletRequest request ->

    // get the path after the method name, so we can proxy the request
    def extraPath = getAdditionalPath(request)

    HttpResponse response = http.request(GET, JSON) {
        uri.path = extraPath
    }

    return Response
        .ok(new JsonBuilder(response.data).toString())
        .header("Access-Control-Allow-Origin", "*") // allows all origins to access resource
        .build()
}

Most of this code is simply involved with proxying the original request through to the official REST API. We make use of the extraPath to capture the location we need to proxy the request to.

To test it you could use

curl -v -X GET -u admin:admin <bitbucket_base_url>/rest/scriptrunner/latest/custom/bitbucketproxy/rest/api/1.0/projects/PROJECTKEY/repos/reposlug

You will notice you get the following header back which allows all domains to access the resource

Access-Control-Allow-Origin: *

Also note that you can have multiple methods with the same name in the same file, which is useful to do simple CRUD REST APIs, eg:

POST /bitbucketproxy - proxy POST requests (create)
PUT /bitbucketproxy - proxy PUT requests (update)
DELETE /bitbucketproxy - proxy DELETE requests (delete)
GET /bitbucketproxy - proxy GET requests (get)

Further Examples

Have questions? Visit the Atlassian Community to connect, share, and learn with other Atlassian users and experts, including Adaptavist staff.

Ask a question about ScriptRunner for JIRA, Bitbucket Server, or Confluence.

Want to learn more? Check out courses on Adaptavist Learn, an online platform to onboard and train new users for Atlassian solutions.