Generating a Java REST Client for Confluence Cloud

Reading Time: 4 minutes

Confluence's REST API has many endpoints, with many combinations of parameters. Getting those data types and parameters correct for everything can be error prone if you were to write the client code manually. Is that a path parameter or a query parameter? Is that parameter optional or required? What data type does that return?

If you only need to talk to a couple of Confluence APIs, or if your system talks to multiple APIs from multiple vendors, you want to make your life easy. Using a code generation tool to write working code to call Confluence can save you a lot of time.

In this post I'll take you through the process of generating Java code from the Open API specification that Atlassian publishes (using swagger-codegen), and then writing a simple Java application that creates a page in Confluence Cloud. Also I'll include some suggestions on best practices for integrating with a cloud service.

Looking for an example of generating a REST API client for Jira instead of Confluence? Check out this tutorial in the Community.

Open API Specification

If you go to the documentation for the Confluence Cloud REST API at The Confluence Cloud REST API you'll see the "…" in the top right. Click that, and you'll see the link for "Download OpenAPI Spec". This is a JSON file that describes the REST API for Confluence Cloud.

The actual link to this file is https://developer.atlassian.com/cloud/confluence/swagger.v3.json . Although swagger-codegen can generate APIs directly from a URL, for now we'll save a copy locally, so save swagger.v3.json somewhere you can find it later.

Swagger and Generating Code

Swagger (or Open API) is a way of documenting APIs in a standard way. I won't discuss that here, but you can read more at API Documentation & Design Tools for Teams | Swagger

While you are welcome to write code by hand to call Confluence's REST APIs, there are a lot of APIs, and new ones are being added all the time. Keeping that code up to date by hand would be time consuming.

I am going to use the swagger-codegen tool to generate my client code. You can build this from source, but I just installed a version on my Mac using "brew install swagger-codegen". Learn more in the project’s README.

I'm going to focus on using Confluence's Open API spec to build a Java client that we can use to call Confluence to create a page.

In theory this is the minimum command you'd need to generate some source code in the current directory from the spec:

swagger-codegen generate \
    -i https://developer.atlassian.com/.../swagger-v3.v3.json \
    -l java \
    -o .

That will generate you a usable client project in the current directory.

In theory you're good to go, but I am going to recommend a few more things as best practice.

Configuring Code Generation Parameters

You will want to do things like choose package names and an HTTP client style that suits your project better. Create a config.json file for swagger-codegen.

For example:

{
    "modelPackage": "com.atlassian.confluence.rest.client.model",
    "apiPackage": "com.atlassian.confluence.rest.client.api",
    "invokerPackage": "com.atlassian.confluence.rest.client",
    "library": "jersey2",
    "groupId": "com.atlassian.confluence.rest",
    "artifactId": "client"
}

I'm using the "jersey2" flavour of HTTP client. There are different options depending on the language you used. Check the documentation for swagger-codegen.

To generate a client using a config file, use a command like

swagger-codegen generate \
    -i ./swagger-v3.v3.json \
    -l java \
    -o ~/src/jira-client
    -c ./config.json

Configure swagger-codegen until you are happy with the code it generates.

Generating the code

The above command generates a Maven/Gradle project under ~/src/jira-client. You will want to customise the pom.xml a bit so suit your development practices, and how you build things that are going to use this code.

Check into version control

While the client code is generated, my recommended best practice is to version control the generated client code. Why? This helps you to know what changed since the last time you generated it.

Using the code

To test, I opened up the generated project directly in my IDE, and created a Main class.

My recommended best practice is to build the generated client as its own Maven library. That way you can refresh the client periodically in a self contained way. Specify this library as a dependency to your projects that need to call Jira.

In this example I'm going to look for a space with my name, create a new page in that space, and return the URL for the new page.

As with other Atlassian REST APIs, I'm going to use Basic authentication. My user name is my email address, and my password is an app token I generated.

public static void main(String[] args) throws ApiException {
    ApiClient apiClient = new ApiClient();
    apiClient.setUsername("myemail@mycompany.com");
    apiClient.setPassword("abcde My app token abcde");
    apiClient.setDebugging(true);
    apiClient.setBasePath("https://myconfluence.atlassian.net");

    // Find my space
    String MY_NAME = "Ben Kelley";
    SpaceApi spaceApi = new SpaceApi(apiClient);
    SpaceArray spaceArray = spaceApi.getSpaces(
        null,  // spaceKey
        null,  // spaceId
        null,  // type
        null,  // status
        null,  // label
        null,  // favourite
        null,  // favouriteUserKey
        null,  // expand
        0,     // start
        1000); // limit
    List<Space> results = spaceArray.getResults();
    Space mySpace = null;
    for (Space space : results) {
        if (space.getName().equals(MY_NAME)) {
            mySpace = space;
            break;
        }
    }
    if (mySpace != null) {
        System.out.println("Found space for " +
            MY_NAME + ": " + mySpace.getKey());
    }

    ContentApi contentApi = new ContentApi(apiClient);
       
    ContentBodyCreate storage = new ContentBodyCreate()
            .representation(ContentBodyCreate.RepresentationEnum.STORAGE)
            .value("This is my page");
    ContentCreateBody body = new ContentCreateBody()
            .storage(storage);
    ContentCreateSpace space = new ContentCreateSpace()
            .key(mySpace.getKey());
    ContentCreate content = new ContentCreate()
            .body(body)
            .type(ContentCreate.TypeEnum.PAGE)
            .space(space)
            .status(ContentCreate.StatusEnum.CURRENT)
            .title("My new page");

    Content created = contentApi.createContent(
            content,
            null,   // status
            null);  // expand
    String link = created.getLinks().get("base") +
            created.getLinks().get("webui");
    System.out.println("Created successfully. URL = " + link);
}

Experimenting with Other Languages

The above should work well with other languages such as Python. However, not all code generation tools for Open API specifications work well with every language, so you might need to do some experimentation to find the settings that work best for your environment.

Have you given this a try for Java or another language? Join the discussion in the Developer Community to share what you learned and what worked for you.