Best practice: Integration Services in OutSystems

Sample based on what3words API

I recently published the first OutSystems forge component to integrate with the Aleph Alpha Public API and considered writing a guide on how to implement integration services for REST APIs. However, due to the API’s size and complexity, I opted to showcase another public API instead. Have you heard of what3words? It’s a solution for communicating precise locations worldwide using human-friendly three-word addresses, rather than GPS coordinates. what3words has divided the earth’s surface into three-by-three-meter squares, each with a unique three-word address. Using their app or API, you can easily convert coordinates to these three words and vice versa.

The simplest way to talk about location


Summary

This tutorial will guide you through the best practices for integrating a REST API in OutSystems, including

  • consuming the API through a driver module and
  • implementing a reusable integration service.

If you’re only interested in obtaining the component, you can scroll to the end of the article for a shortcut.

What you need

If you want to follow up the implementation on your own, you need:

  • An OutSystems account (a free personal environment is sufficient)
  • OutSystems Service Studio
  • what3words account and API key (will be created in this tutorial)

For this tutorial you should already have some experience in building applications with OutSystems.


Register for your what3words API key

Before utilizing what3words’ API, you will need to register for an account and generate an API key:

  • Go to https://developer.what3words.com/ and click the button Get an API Key.
  • Choose the plan of your liking (free plan is sufficient for this tutorial).
  • Sign up or log in via your preferred method.
  • Accept the terms and conditions.
  • Optionally type in your company and industry information.
  • In step Create an API Key fill in a name (e.g. OutSystems Connector) and a brief description of your project and click Generate API Key.

It’s also possible to limit the usage of your API key, but for the purposes of this tutorial, you can leave the checkbox Add API Key restriction unchecked.


Architecture

OutSystems simplifies the process of consuming REST APIs, even directly in your UI module. However, this can result in multiple integrations of the same API, which can make code maintenance difficult. To address this, it’s recommended to encapsulate the API integration in a dedicated integration service, which can be utilized by various OutSystems applications in your environment.

The integration architecture consists of two module types:

  • Integration Service
    provides the integrated functionality to your environment and can be seen as the facade towards applications.
  • Driver
    is the interface to the consumed external service and connects to its provided API endpoints.

The purpose of this division into two parts is to decouple between both sides. So only minimal adjustments are required when changes occur. You do not want to change all applications in your environment when the external service changes an API endpoint or releases a new version.


Create the service application

To begin, create a new application called what3words Connector. Since this will only include our new integration service and doesn’t have its own UI, we select Service as the application type.

After clicking on Create App, OutSystems opens the new application and asks for the first module to be created.

Implementing the driver module

Let’s begin with creating the driver module. Following OutSystems’ naming convention, we name the module what3words_DRV. The suffix _DRV is denoting its functional role as a driver. We keep the preselected Service option in the module type dropdown and click Create Module.

Of course, the main functionality of the API is the two conversion endpoints. As you will see later in this tutorial, they are a little bit special. Thats why I decided to start with the easiest endpoint:

First simple endpoint: Available languages

This endpoint returns a list of all available languages used for valid three-word addresses.

  • On the Logic tab in Service Studio open the Integrations folder.
  • Right click on REST and click on Consume REST API…

In the opening dialog, you have the option to add a single method or multiple methods. The second option is only applicable if you have a Swagger definition of the endpoint(s) you wish to consume. For this tutorial, we choose the first option to demonstrate all steps in detail.

  • Select Add single method and click on Continue.

In the next dialog we need to configure the REST call to be made. It is always a clever idea to inspect the API documentation first. For what3words you can find the documentation here:

API Reference Docs | what3words

The most important setting are the HTTP verb and the URL of the endpoint to be consumed.

YAML
HTTP Method: GET
URL: https://api.what3words.com/v3/available-languages
  • Leave the HTTP method unchanged and copy and paste the endpoint’s URL to the dialog.

As you can see from the API docs sample, we must pass the API key to authenticate. The sample shows passing it as a parameter key in the URL but what3words also offers to pass it in a custom header. To demonstrate how data can be sent in header variables, we will use this option here.

  • Switch to the Headers and Authentication tab and enter the request header X-Api-Key.

To get the response structure for the REST method, we can copy and paste the result JSON from the API documentation. Alternatively, we can switch to the Test tab of the dialog, fill in the API key in the X-Api-Key parameter, and click the Test button. This will invoke the request and show the result. If successful, we can apply the result by clicking Copy to response body.

Regardless of the method we choose, it’s important that the response body field contains the JSON structure with sample data. Here I omitted most of the languages to save you from scrolling. If all returned fields and values of the respective data types are present, OutSystems can determine the required structures.

JSON
{
  "languages": [
    {
      "nativeName": "Deutsch",
      "code": "de",
      "name": "German"
    },
    {
      "nativeName": "हिन्दी",
      "code": "hi",
      "name": "Hindi"
    }
  ]
}

To generate the REST consumer action, click Finish and let’s see what has been generated so far:

As you can see, there now is a new REST integration called What3words with one action GetAvailablelanguages to invoke the GET request. On Data tab you find a What3words item with structures generated for the response.

The API key is used for authentication and thus should be treated like a password. As the request is made over HTTPS the key is encrypted in transport, but we should change a setting in the Logic tab:

  • Go to the input parameter XApiKey and change Log Reduction to Yes. This will hide the key from the log.

I personally recommend filling in descriptions for the REST action and its parameters as well as for the generated structures and their attributes. Normally I just copy the respective texts from the official API docs.

I also rename the REST action in Pascal case for better readability and move the HTTP verb to the end. In our case GetAvailablelanguages becomes AvailableLanguages_Get. This will group all actions invoking the same endpoint with different HTTP verbs (GET, POST, PUT, etc.). The structures I rename the following way, which I will explain later in this article.

JavaScript
/**
 * @structure What3words_AvailableLanguages_GetResponse
 * Response of available languages endpoints
 *
 * @attribute {What3words_Language List} [Languages]
 * List of available languages
 */

/**
 * @structure What3words_Language
 * Available language
 *
 * @attribute {Text} [NativeName]
 * Native name
 *
 * @attribute {Text} [Code]
 * ISO 3166-1 alpha-2 2 letter code
 *
 * @attribute {Text} [Name]
 * Name
 */

Using URL parameters: Conversion endpoints

Everything was simple so far, wasn’t it? Next, we will implement the two conversion endpoints for converting three-word addresses to coordinates and vice versa.

  • As the What3words integration is already present in our module, we can now add additional methods by simply right clicking it on the Logic tab and select Add REST API Method… from the context menu.
  • For the dialog just follow the same steps we did for the first endpoint.

As you can see in the API documentation, both conversion endpoints await some URL parameters. We can use placeholders for this in OutSystems by simply replacing the value parts in the URL by the name of the parameter we later want to use in OutSystems, enclosed in curly brackets:

YAML
# Convert to three-word address
HTTP Method: GET
URL: https://api.what3words.com/v3/convert-to-3wa?coordinates={Coordinates}&language={Language}&format={Format}

# Convert to coordinates
HTTP Method: GET
URL: https://api.what3words.com/v3/convert-to-coordinates?words={Words}&format={Format}

As we saw while adding the first endpoint, OutSystems helps us with the automatic creation of the respective response structures if we provide sample response data. So, let’s make use of this assistance and copy the response of the json format:

JavaScript
{
  "country": "GB",
  "square": {
    "southwest": {
      "lng": -0.195543,
      "lat": 51.520833
    },
    "northeast": {
      "lng": -0.195499,
      "lat": 51.52086
    }
  },
  "nearestPlace": "Bayswater, London",
  "coordinates": {
    "lng": -0.195521,
    "lat": 51.520847
  },
  "words": "filled.count.soap",
  "language": "en",
  "map": "https://w3w.co/filled.count.soap"
}

Once you have completed the dialog for both methods, also rename the REST methods accordingly:

  • Rename GetConverttocoordinates to ConvertToCoordinates_Get and
  • GetConvertto3wa to ConvertToThreeWordAddress_Get.

For the generated structures, you will notice that the ones already present are reused. This is because OutSystems attempts to reuse structures if they match, and sometimes even extends them. If you do not want to reuse them, you can manually copy structures and modify the data types of the REST action parameters as needed.

Structures of the REST integration

In our case, we know that the API returns the same response structure for both conversion endpoints. Therefore, it is reasonable to rename the structures and provide descriptions as well. In addition, meaningful names help with later assignment and prevent naming conflicts with other structures that we still need to implement further below.

While implementing the first endpoint /available-languages I renamed the structures in a special manner, and promised to explain my personal naming preferences:

  • All structures of the integration are prefixed with the integration’s name and an underscore to generate a unique namespace for them.
  • Structures for the request or response body (root level only) are named analog to the REST methods using them followed by Response or Request.
  • Structures for nested data objects are named by the name of the object. If a nested data object has differing endpoint or request/response specific representations, the specific method’s name or Response/Request is also part of the prefix.
  • When names would otherwise become too long, middle parts can be omitted or abbreviated, while trying to remain a most senseful sorting order.

For our example this results in the following What3words structures:

JavaScript
/**
 * @structure What3words_Convert_GetResponse
 * Response of conversion endpoints
 *
 * @attribute {Text} [Country]
 * Uppercase ISO 3166-1 alpha-2 country code
 *
 * @attribute {What3words_Square} [Square]
 * Square coordinates
 *
 * @attribute {Text} [NearestPlace]
 * Nearest place (e.g. city)
 *
 * @attribute {What3words_Coordinates} [Coordinates]
 * Coordinates
 *
 * @attribute {Text} [Words]
 * Three-word-address
 *
 * @attribute {Text} [Language] = "hidden"
 * ISO 639-1 2 letter code of the 3 word address language
 *
 * @attribute {Text} [Map]
 * Link to the address on the what3words website
 */

/**
 * @structure What3words_Coordinates
 * Coordinates
 *
 * @attribute {Decimal} [Lng]
 * Longitude
 *
 * @attribute {Decimal} [Lat]
 * Latitude
 */

/**
 * @structure What3words_Square
 * Square coordinates
 *
 * @attribute {What3words_Coordinates} [Southwest]
 * Southwest coordinates of the square
 *
 * @attribute {What3words_Coordinates} [Northeast]
 * Northeast coordinates of the square
 */

Dynamic response structures: Conversion endpoints

So far so good, were it not for the viable alternative response format geojson, which does not fit into the now generated structure. So how can we handle this?

For our integration we want to have the default format json parsed into the already generated structure for easy consumption. But the second format might also become handy to receive for applicable use cases that expect the geojson as text. To allow for both use cases, we need to make some adjustments:

  • Go to the Logic tab and select both conversion REST actions.
  • In the properties area change the Response Format from JSON to Plain Text.
  • Change the Data Type of the Response parameters from What3words_Convert_GetResponse to Text.

This will make the former assigned response structures obsolete but please just keep them for now, as we will need them later.

The what3words API provides some more endpoints, but for this tutorial we concentrate on the three already added methods only.

Public objects for the integration service

All objects implemented so far are private, so they are only available within the driver module. Since they are fully dependent on the API and we do not want to pass this dependency on to the integration service, we now need to write corresponding public wrappers that can be used by the what3words_IS module. In addition, errors can occur when calling the API, which we must handle accordingly.

Structures of the driver module

Of course, this also requires structures for transferring the data. The driver is only an abstraction between the integration service and the API endpoints. So, the public structure should not differ from the private ones already existent. Thus, for now, we can simply copy them and make them public. Here we benefit from already having named and filled in descriptions, since these are now kept when copying.

You will see, that OutSystems is appending a number 2 at the end of all structure names. This is why I rename the public structures by removing the integration’s name prefix and the number at the end:

JavaScript
/**
 * @structure AvailableLanguages_GetResponse
 * Response of available languages endpoints
 *
 * @attribute {Language List} [Languages]
 * List of available languages
 */

/**
 * @structure Language
 * Available language
 *
 * @attribute {Text} [NativeName]
 * Native name
 *
 * @attribute {Text} [Code]
 * ISO 3166-1 alpha-2 2 letter code
 *
 * @attribute {Text} [Name]
 * Name
 */

/**
 * @structure Convert_GetResponse
 * Response of conversion endpoints
 *
 * @attribute {Text} [Country]
 * Uppercase ISO 3166-1 alpha-2 country code
 *
 * @attribute {Square} [Square]
 * Square coordinates
 *
 * @attribute {Text} [NearestPlace]
 * Nearest place (e.g. city)
 *
 * @attribute {Coordinates} [Coordinates]
 * Coordinates
 *
 * @attribute {Text} [Words]
 * Three-word-address
 *
 * @attribute {Text} [Language] = "hidden"
 * ISO 639-1 2 letter code of the 3 word address language
 *
 * @attribute {Text} [Map]
 * Link to the address on the what3words website
 */

/**
 * @structure Coordinates
 * Coordinates
 *
 * @attribute {Decimal} [Lng]
 * Longitude
 *
 * @attribute {Decimal} [Lat]
 * Latitude
 */

/**
 * @structure Square
 * Square coordinates
 *
 * @attribute {Coordinates} [Southwest]
 * Southwest coordinates of the square
 *
 * @attribute {Coordinates} [Northeast]
 * Northeast coordinates of the square
 */

For each REST method we now implement a public server action that wraps the call to the API.

  • The name is equal to the called REST method, but prefixed with the integration’s name and API version, separated by an underscore.

The simplest way to support both response formats of the conversion methods is to expose separate server actions for json (output as structure) and geojson (output as text). For the geojson variant just append GeoJson to the action’s name.

Afterwards, we need to add all input and output parameters. While you can simply copy and paste them from the REST method, it is important to ensure:

  • The Mandatory property of all required input parameters is set to Yes.
  • The Data Type of all parameters is changed to the according public structures.

You should end up with the following five server actions:

JavaScript
/**
 * @action What3words_v3_AvailableLanguages_Get
 * Retrieves a list of all available 3 word address languages, including
 * the ISO 3166-1 alpha-2 2 letter code, english name and native name.
 *
 * @input {Text} XApiKey
 * A valid API key
 *
 * @output {AvailableLanguages_GetResponse} Response
 * Response of available languages endpoints
 */

/**
 * @action What3words_v3_ConvertToCoordinates_Get
 * This function converts a 3 word address to a latitude and longitude.
 * It also returns country, the bounds of the grid square, a nearest place
 * (such as a local town) and a link to our map site.
 *
 * @input {Text} XApiKey
 * A valid API key
 *
 * @input {Text} Words
 * A 3 word address as a string. It must be three words separated with dots
 * or a japanese middle dot character (・). Words separated by spaces will
 * be rejected. Optionally, the 3 word address can be prefixed with ///
 * (which would be encoded as %2F%2F%2F)
 *
 * @output {Convert_GetResponse} Response
 * Result of conversion endpoints
 */

/**
 * @action What3words_v3_ConvertToCoordinates_GetGeoJson
 * This function converts a 3 word address to a latitude and longitude.
 * It also returns country, the bounds of the grid square, a nearest place
 * (such as a local town) and a link to our map site.
 *
 * @input {Text} XApiKey
 * A valid API key
 *
 * @input {Text} Words
 * A 3 word address as a string. It must be three words separated with dots
 * or a japanese middle dot character (・). Words separated by spaces will
 * be rejected. Optionally, the 3 word address can be prefixed with ///
 * (which would be encoded as %2F%2F%2F)
 *
 * @output {Text} Response
 * GeoJSON
 */

/**
 * @action What3words_v3_ConvertToThreeWordAddress_Get
 * This function will convert a latitude and longitude to a 3 word address,
 * in the language of your choice. It also returns country, the bounds of
 * the grid square, a nearby place (such as a local town) and a link to our
 * map site.
 *
 * @input {Text} XApiKey
 * A valid API key
 *
 * @input {Text} Coordinates
 * Coordinates as a comma separated string of latitude and longitude
 *
 * @input {Text} [Language]
 * A supported 3 word address language as an ISO 639-1 2 letter code.
 * Defaults to en (english). For a full list of 3 word address languages,
 * see available-languages.
 *
 * @output {Convert_GetResponse} Response
 * Result of conversion endpoints
 */

/**
 * @action What3words_v3_ConvertToThreeWordAddress_GetGeoJson
 * This function will convert a latitude and longitude to a 3 word address,
 * in the language of your choice. It also returns country, the bounds of
 * the grid square, a nearby place (such as a local town) and a link to our
 * map site.
 *
 * @input {Text} XApiKey
 * A valid API key
 *
 * @input {Text} Coordinates
 * Coordinates as a comma separated string of latitude and longitude
 *
 * @input {Text} [Language]
 * A supported 3 word address language as an ISO 639-1 2 letter code.
 * Defaults to en (english). For a full list of 3 word address languages,
 * see available-languages.
 *
 * @output {Text} Response
 * GeoJSON
 */

Now it is time to implement the logic flow. For all actions:

  • Simply drag the respective REST method from the Logic tab to your flow.
  • Fill in all its parameters by mapping them to the corresponding input parameters.

For What3words_v3_AvailableLanguages_Get and both _GetGeoJson actions:

  • Add an assign element beneath and assign the REST action’s Response to the output parameter Response.

For both other conversion actions we need to parse the response ourselves:

  • To do this, add a JSON Deserialize node and pass in the REST action’s Response as JSON String and select Convert_GetResponse as Data Type.
  • Add an assign element beneath and assign JSONDeserializeConvert_GetResponse.Data to the output parameter Response.

Error handling

The last missing feature of our driver module is error handling. There are a lot of things that can go wrong when calling the API, for example the API will return:

  • HTTP 401 when the API key is missing or invalid
  • HTTP 400 when the request was bad (e.g. missing a required parameter)
  • HTTP 50x when an internal server error occurs

So, let’s begin with implementing an exception that can be thrown when an error occurs. On Logic tab scroll to the end, unfold Exceptions and All Exceptions and right click User Exception to Add User Exception. Name the new exception ApiException.

According to the API documentation, it provides some JSON-formatted details on the error in the response body as well:

JSON
{
  "error": {
      "code": "BadWords",
      "message": "Invalid or non-existent 3 word address"
  }
}

To parse this, we create two new structures called ErrorResponse and Error with the following attributes. You can quickly create new structures in OutSystems from a sample JSON and afterwards adjust them:

  • Right click on the Structures folder on Data tab and select Add Structure from JSON…
  • Copy and paste the sample error response JSON.
  • Adjust naming and add descriptions:
JavaScript
/**
 * @structure ErrorResponse
 * API response in case of an error
 *
 * @attribute {Error} [Error]
 * Error details
 */

/**
 * @structure Error
 * Error details
 *
 * @attribute {Integer} [StatusCode]
 * The HTTP status code received from the API.
 *
 * @attribute {Text} [StatusLine]
 * The name of the HTTP status code received from the API.
 *
 * @attribute {Text} [Code]
 * Parsed error code received from the API.
 *
 * @attribute {Text} [Message]
 * Parsed error message received from the API.
 */

ErrorResponse will only be used inside the driver and can stay non-public. Error is also used to pass error details to the integration service, so we need to make it public.

To parse the error response body, we implement the additional server action named TryAndParseApiError.

  • Add an input parameter TextToParse of type Text.
  • Add an output parameter Error of type Error.
  • Add a JSON Deseralize item to the flow and name it DeserializeError.
  • Pass the input parameter TextToParse to the JSON String property and select ErrorResponse as Data Type.
  • Add an Assign item beneath and assign DeserializeError.Data.Error to the output parameter Error.

If an error occurs during parsing, we simply return the TextToParse as Error.Message. Don’t forget to change the Abort Transaction property of the AllExceptions handler to No. Otherwise, we would abort transactions of a consumer app which might not be intended.

To catch the error when needed, we have to react to the OnAfterResponse event of the REST integration. To add this event handler

  • navigate to the What3words integration,
  • open the dropdown On After Response,
  • and select New OnAfterResponse.

This will create a new action where we can check for the HTTP response status code and try to parse the error details in the response body:

  • Add an If item with condition CustomizedResponse.StatusCode >= 400.
  • Move the False branch with the End item to the right, as the event handler can return when no error occurred.
  • Drag the action TryAndParseApiError to the True branch and pass Response.ResponseText to the TextToParse parameter.
  • Assign Response.StatusCode and Response.StatusLine to the corresponding attributes of TryAndParseApiError.Error.
  • Finally, JSON-serialize the error and throw a new ApiException with the serialized error as Exception Message.

Now that we will get an ApiException whenever a REST endpoint of What3words returns with a HTTP error, we must also catch this exception in our wrapping server actions. For this we need another helper action to parse the error details in the ApiException:

  • Add an input parameter TextToParse of type Text.
  • Add an output parameter Error of type Error.
  • Add a JSON Deseralize item to the flow and name it DeserializeError.
  • Pass the input parameter TextToParse to the JSON String property and select Error as the Data Type.
  • Add an Assign item beneath and assign DeserializeError.Data to the output parameter Error.

As in TryParseApiError catch all exceptions (without aborting the transaction) and return the TextToParse as Error.Message.

Now we can extend all public server actions with the following exception handler flow:

  • Add two output parameters: IsSuccess of type Boolean, and Error of type Error to the action.
  • Add an ApiException handler to the flow and don’t forget to change the Abort Transaction property to No.
  • Drag the TryParseError server action to the flow and pass ApiException.ExceptionMessage as TextToParse.
  • Assign IsSuccess = False and Error = TryAndParseError.Error and end the event handler flow.
  • Don’t forget to add IsSuccess = True as an assignment in item Response of the main flow.

Everything is implemented for the driver now. Before we publish the module, we should remove all unused dependencies by clicking Remove Unused Dependencies in the Module menu.

Implementing the integration service

Now that the driver module is complete, we can implement the integration service. So, go to the application overview in Service Studio and add a new module named what3words_IS of type Service. The integration service uses the driver to call the what3words API, so we need to add dependencies to the public actions of our driver. The structures are selected automatically:

Structures of the integration service

Do you remember the architectural idea behind the separation between driver and integration service? We want to achieve decoupling of the external service and other applications in our environment. Therefore, it makes sense to create all data structures that should be used by consumers of the integration service again in the what3words_IS module. This will prevent later dependencies of consuming apps on the driver module.

To ease our work, we can copy and paste the structures again and then adjust them:

  • I prefer to prefix the structures’ names with the integration’s name. This will become handy in consuming apps as it creates a namespace for the integration and reduces naming conflicts.
  • To abstract the external functionality, I modify names to be more general, without representing every technical detail only relevant to the driver. Additionally, the integration service may convert data and structures to be consumed by other developers more easily. However, I take care not to completely detach from the external service’s API, so the interface remains comprehensible.
  • OutSystems automatically exchanges data types of nested structures if you copy and paste them all at once. Nevertheless, you should double check none of the driver’s structures are referenced in the new structures.
JavaScript
/**
 * @structure What3words_Conversion
 * Result of a conversion from coordinates to 3-word-address and vice versa
 *
 * @attribute {Text} [Country]
 * Uppercase ISO 3166-1 alpha-2 country code
 *
 * @attribute {What3words_Square} [Square]
 * Square coordinates
 *
 * @attribute {Text} [NearestPlace]
 * Nearest place (e.g. city)
 *
 * @attribute {What3words_Coordinates} [Coordinates]
 * Coordinates
 *
 * @attribute {Text} [Words]
 * Three-word-address
 *
 * @attribute {Text} [Language]
 * ISO 639-1 2 letter code of the 3-word-address language
 *
 * @attribute {Text} [Map]
 * Link to the address on the what3words website
 */

/**
 * @structure What3words_Coordinates
 * Coordinates
 *
 * @attribute {Decimal} [Lng]
 * Longitude
 *
 * @attribute {Decimal} [Lat]
 * Latitude
 */

/**
 * @structure What3words_Error
 * Error details
 *
 * @attribute {Integer} [StatusCode]
 * The HTTP status code received from the API.
 *
 * @attribute {Text} [StatusLine]
 * The name of the HTTP status code received from the API.
 *
 * @attribute {Text} [Code]
 * Parsed error code received from the API.
 *
 * @attribute {Text} [Message]
 * Parsed error message received from the API.
 */

/**
 * @structure What3words_Language
 * Available language
 *
 * @attribute {Text} [NativeName]
 * Native name
 *
 * @attribute {Text} [Code]
 * ISO 3166-1 alpha-2 2 letter code
 *
 * @attribute {Text} [Name]
 * Name
 */

/**
 * @structure What3words_Square
 * Square coordinates
 *
 * @attribute {What3words_Coordinates} [Southwest]
 * Southwest coordinates of the square
 *
 * @attribute {What3words_Coordinates} [Northeast]
 * Northeast coordinates of the square
 */

Service actions of the integration service

As for structures, the same applies to server actions. To achieve the targeted decoupling, the integration service provides its own public actions for consuming apps.

  • Same as with structures, I create a namespace for the integration by prefixing the actions’ names with the integration’s name.
  • For all input and output parameters we use the What3words_* structures we recently created, of course.

As part of the abstraction process, I also implement some conversions in the IS module to make the integration consumable more easily. The function for converting coordinates to a three-word address, for example, expects a comma-separated string on the API side, although coordinates are returned in a structure with attributes for latitude and longitude. So, we can reuse this for input parameters as well. To demonstrate this, let’s

  • implement the input parameter Coordinates with type What3words_Coordinates and convert the value accordingly before passing it to the driver.
  • Of course, we change the Mandatory property of Lat and Lng to Yes.

When assigning the output structures, OutSystems automatically tries to map all attributes based on their names and datatypes. For nested structures this does not always work:

  • In simple cases, you can select the proper attribute (e.g. Coordinates.Lng = Coordinates.Lng) from the dropdown.
  • If the nested attribute is a structure itself, you must assign it in a separate assignment (e.g. Response.Square.Southwest = What3words_v3_ConvertToCoordinates_Get.Response.Square.Southwest).
  • Nested lists sometimes require you to loop through and append items separately to a local variable that can afterwards be assigned to the output structure.

Congrats, you have made it through! Don’t forget to clean up the dependencies and publish.


Get the ready-to-use component from the forge

I published the what3words Connector including all API methods (except speech recognition) in the OutSystems Forge. This also comes with a small demo app so you can try out things and directly use it in your own apps. I would be happy if you leave a like in the forge.

I hope the article was interesting for you and would be pleased if you follow me on my social media accounts. In case you have any questions left open or have tips for me to improve, please contact me via Medium or my OutSystems profile.

More posts