◂ Back to Profiq blog

How to develop a MuleSoft connector

GitLab logo

Introduction

After a brief introduction to the MuleSoft platform in my

first blog

, I would like to share my first experience with developing a connector. I decided to develop a

Gitlab

connector because it is a great system and I did not find a connector that would be developed for it.

First, I’m going to focus on describing the options you have when you decide to develop a connector. Next, I will describe, how to structure the connector and what are the specifics that you need to care of in comparison to the development of a standard Java program.

Development options

You have basically three options when deciding about the way to develop your connector. You can choose to develop the connector based on Java SDK for your app, with SOAP approach or as RESTfull API. You can read more about this in the

official documentation

.

Gitlab has a

Java SDK

available, so I have chosen to develop the connector that way. It has the advantage that I do not have to bother with low-level logic (such as how to call a GET request and others) because the Gitlab Java SDK solves this for me. I just call appropriate methods from the SDK.

If there is no Java SDK available for your project, you will have to develop it from scratch. You can automate parts of this task, such as code generation from YAML API specification, but describing it goes beyond the scope of this article.

Structure

The structure is briefly described in the MuleSoft

documentation

so I will do just a quick high-level introduction here.

Most fundamentally the connector consist of two parts. The config class and the connector itself. The config class stores the data related to the connector instance. In my case, it is the username, password, and the Gitlab host URL. There is also the option to enter API key but the connector is able to obtain it automatically based on the username and password too. The config also contains read-only API endpoint pointer which is the gate to all API calls. It is established after connecting to the Gitlab with credentials. All the connection and disconnection logic is located in the config class too.

@ConnectionManagement(friendlyName = "Configuration")
public class ConnectorConfig {
    @Configurable
    @Default("https://gitlab.com")
    private String gitlabHost = "https://gitlab.com";

    @Configurable
    @Optional
    private String privateToken;

    @Connect(strategy = ConnectStrategy.SINGLE_INSTANCE)
    public void connect(@ConnectionKey final String username, @Password final String password, @Optional final Boolean ignoreCertificationErrors, @Optional final Integer requestTimeout) throws ConnectionException {
        ... // Connection logic
    }

    @Disconnect
    public void disconnect() {
        ... // Disconection logic
    }

    @TestConnectivity
    public void testConnectivity(@ConnectionKey final String username, @Password final String password, @Optional final Boolean ignoreCertificationErrors, @Optional final Integer requestTimeout) throws ConnectionException {
        ... // Test connectivity logic
    }

    @ValidateConnection
    public boolean isConnected() {
        ... // Validation connection logic
    }
}

All processor methods that call the Gitlab API are included in the connector class. You could implement most of the methods with just one line by calling the appropriate SDK method. I decided to improve the code by adding logging and exception handling. I also decided that processors inputs will be just basic data types (Integer, String, etc.) and enums in some cases. The choice was made to unify the approach (SDK mismatches that it sometimes requires the class, while sometimes just the ID of the element) and simplify the usage of the connector. I often used annotation “FriendlyName” too to make the connector look more consistent.

Here is an example processor:

@Processor
public GitlabMergeRequest acceptMergeRequest(@FriendlyName("Project ID") final Integer projectId, @FriendlyName("Merge Request ID") final Integer mergeRequestId, @Optional final String mergeCommitMessage) throws IOException {
    final GitlabProject project;
    final GitlabMergeRequest result;

    LOGGER.trace("Trying to load project {}...", projectId);
    try {
        project = this.config.getApiHandler().getProject(projectId);
    }
    catch (final IOException ex) {
        LOGGER.error("Project {} was not loaded.", projectId);
        throw ex;
    }
    if (project == null) {
        LOGGER.error("Project {} was not loaded (return \"null\").", projectId);
        throw new IOException("Project was not loaded (return \"null\").");
    }
    LOGGER.debug("Project {} was loaded correctly.", projectId);

    LOGGER.trace("Trying to accept merge request {}...", mergeRequestId);
    try {
        result = this.config.getApiHandler().acceptMergeRequest(project, mergeRequestId, mergeCommitMessage);
    }
    catch (final IOException ex) {
        LOGGER.error("Accepting merge request {} failed.", mergeRequestId);
        throw ex;
    }
    if (result == null) {
        LOGGER.error("Accepting merge request {} failed (return \"null\").", mergeRequestId);
        throw new IOException("Accepting merge request failed (return \"null\").");
    }
    LOGGER.debug("Merge request {} was accepted correctly.", mergeRequestId);

    return result;
}

If you would like to see the complete connector, you can find and download it on

Github

. You are welcome to use it and improve it through fork and pull request. Looking forward to hearing your feedback.

Filip Vavera

Written by

Filip Vavera

Comments

Leave a Reply

Online comments are not active during the static migration phase.
AI Function Blog Image

Is The Most Valuable AI Function Asking Better Questions?

How the "Grill Me" method became a key part of Project Weaver's approach to AI-assisted software development. We've shared some of the thinking behind Project Weaver—the internal engineering framework we've developed at profiq to help our teams and AI work together more effectively. Rather than treating AI as a magic code generator, Weaver is built around a simple idea: the better the structure, context, and engineering discipline, the better the outcomes.

Posted 4 weeks ago by Anke Corbin

Weaver Prototype Image

From Vibe-Coded Prototype to Production-Ready App Using Weaver

There's an important distinction between a prototype that demonstrates an idea and a system that can support a real business. Recently, we had the opportunity to explore that distinction firsthand while working with Ginger & Nash on an application called c.h.i.p. using profiq Weaver as an AI assistant.

Posted 5 weeks ago by Anke Corbin

Project Weaver Recap

Quick Recap: Project Weaver Engineering Series

We wanted to do another quick recap of the Weaver journey so far for those of you who are just learning about the project, from the first idea through the latest automation and workflow experiments.

Posted 2 months ago by Anke Corbin

Read the Blog