Skip to main content
Version: 0.7.0

Client Generator

The OpenAPI Generator for OpenEdge ABL produces enterprise-ready client libraries with advanced features for API consumption, including comprehensive model builders, HTTP client management, and flexible configuration options.

Prerequisites

1. Setup OpenEdge Project in VSCode

  1. Create a new folder for your OpenEdge project (e.g., openapi_client)
  2. Open the folder in VSCode

Initialize Project Configuration

Use the API4UI Toolbox for easy project initialization (recommended):

  1. Right-click your project folder in VSCode Explorer
  2. Select API4UI Toolbox > ABL > Initialize > Initialize Project Configuration
  3. This creates the required openedge-project.json file for the Riverside extension

Alternatively, follow the VSCode ABL Github page for manual project configuration.

Configure Project

Configure your OpenEdge project according to your environment. The Riverside extension requires proper configuration for ABL language features to work correctly.

Note: Detailed configuration steps are beyond the scope of this guide. Refer to Riverside's documentation or use the API4UI Toolbox for guided setup.

2. Launch OpenAPI Generator Extension

  1. Open VSCode Command Palette (Ctrl + Shift + P / Cmd + Shift + P)
  2. Type and select: "Launch OpenAPI generator 😎 (vscode sync)"

Configure Generation Settings

  1. Choose Generation Type: Select Client from the dropdown
  2. Choose Language: Select abl
  3. Configure Settings: Click the Settings button to open the configuration panel

General Settings:

  • packageName: Set your desired package name (default: "OpenAPI" if not specified)

Note: These settings will be saved to .vscode/settings.json and should be committed to version control for team consistency.

Select OpenAPI Specification

  1. Click Browse next to "Select file"
  2. Choose your OpenAPI specification file (.yaml or .json)

Generate Code

  1. Ensure Project Path is set to your current project folder
  2. Click Sync to Selected Location

The generated code will be placed directly in your project folder under the specified package name.

Example Specs: Download this example spec to test the generator

GIF: VSCode OpenAPI Generator Extension 0.7.0 (Client)

Load Saved Settings

When reopening the extension later:

  1. Click Load Settings at the top
  2. Select from previously saved configurations
  3. Settings will be restored automatically

GIF: VSCode OpenAPI Generator Extension 0.7.0 (Load Settings)

3. Project Structure

The generated ABL client library follows this structure:

[package]/
├── Apis/ # API client classes for each endpoint group
├── Factories/ # HTTP client service factories
├── Helpers/ # Helpers used by the generated code
├── Models/ # Data model classes
│ ├── ApiRequests/ # Request models for API operations
│ │ └── Builders/ # Builder classes for request models
│ ├── ApiResults/ # Response models for API operations
│ ├── Builders/ # Builder classes for schema models
│ ├── Collections/ # Collection wrapper classes
│ └── *.cls # Schema models from OpenAPI spec
├── Services/ # HTTP client services and utilities
└── logging.config # Logging configuration

4. Configuration

To configure the client library, you need to set up your HTTP Client Service with the necessary credentials and any required settings.

When initializing a new API class instance without input parameters, the library will automatically retrieve the configuration from the HttpClientServiceFactory. You can also pass in a HttpClientService instance or the API Name configured in the factory.

By default, the library targets the API base path defined in the OpenAPI Spec Servers (first). You can override this by setting the basePath property in the HttpClientConfiguration.

Note: The current setup for loading the initial config has to be revised. A more practical solution/implementation will be provided in a later version.

5. Builder Pattern

The generated library uses a fluent builder pattern for creating complex model objects. This pattern provides method chaining, automatic list initialization, and support for nested object creation.

Simple Models

For basic models with primitive properties:

using Orders.Models.Builders.PetBuilder.

var Pet oPet = new PetBuilder()
:SetName("Fluffy")
:SetId(123)
:SetStatus("available")
:Build().

Complex Models with Nested Objects

For models containing other model objects, you can use nested builders:

using Orders.Models.Builders.PetBuilder.
using Orders.Models.Builders.CategoryBuilder.

var Pet oPet = new PetBuilder()
:SetName("Fluffy")
:SetId(123)
:SetCategory(new CategoryBuilder()
:SetName("Dogs")
:SetId(1)
)
:SetStatus("available")
:Build().

Models with Lists

The builder pattern includes convenience methods for working with lists:

using Orders.Models.Builders.PetBuilder.
using Orders.Models.Builders.TagBuilder.

var Pet oPet = new PetBuilder()
:SetName("Fluffy")
:SetId(123)
:AddTag(new TagBuilder()
:SetName("friendly")
:SetId(1)
)
:AddTag(new TagBuilder()
:SetName("playful")
:SetId(2)
)
:AddPhotoUrlsString("http://example.com/photo1.jpg")
:AddPhotoUrlsString("http://example.com/photo2.jpg")
:SetStatus("available")
:Build().

Note: The AddTag() and AddPhotoUrlsString() methods automatically initialize the lists if they don't exist, making it easy to build complex objects without manual list management.

Model Builders with Default Values

This functionality will be implemented in a future version (soon).

6. API Usage Examples

Making API Requests

Here's a complete example of making an API request with a complex model:

block-level on error undo, throw.

using Orders.Apis.OrdersApi.
using Orders.Models.*.
using Orders.Models.ApiRequests.GetOrdersRequest.
using Orders.Models.ApiResults.GetOrdersResult.

var OrdersApi oOrdersApi.
// If the request contains models, you can build them here using the Model Builders
var GetOrdersRequest oRequest.
var GetOrdersResult oResult.

oOrdersApi = new OrdersApi().
oRequest = new GetOrdersRequest().
// Set all properties needed to have a valid request, each property has a public Set method.

oResult = oOrdersApi:GetOrders(oRequest).

// The result object has an IsSuccess logical, set to true when the statuscode is not larger than 299.
// You can also use the oResult:StatusCode (integer) or oResult:StatusCodeEnum to handle every case.
if oResult:IsSuccess
then do:
/* The Result object contains the data for each possible response type described in the OpenAPI Spec.
The property has the name of the StatusCodeEnum for the responses statuscode + Data, e.g. 200 = OkData.

Here you can extract the correct data and perform any extra logic needed for your use case.
*/
end.

Handling Responses

The Result objects provide multiple ways to handle API responses:

var AddPetResult oResult = oPetApi:AddPet(oRequest).
var Pet oCreatedPet.
var StringMap oErrors.

// Method 1: Check IsSuccess property
if oResult:IsSuccess
then do:
// Handle successful response
oCreatedPet = oResult:OkData. // For 200 responses
end.

// Method 2: Check specific status codes
if oResult:StatusCode = 200
then do:
oCreatedPet = oResult:OkData.
end.
else if oResult:StatusCode = 400
then do:
// Handle validation errors
oErrors = oResult:BadRequestData.
end.

// Method 3: Use StatusCodeEnum
case oResult:StatusCodeEnum:
when "Ok" then do:
oCreatedPet = oResult:OkData.
end.
when "BadRequest" then do:
oErrors = oResult:BadRequestData.
end.
otherwise do:
message substitute("Unexpected status: &1", oResult:StatusCode).
end.
end case.

7. Logging

To enable logging for this library, you'll need to configure the logging.config file. Logging is handled using the OpenEdge.Logging.* classes.

Default Configuration

This library includes a logging.config file with a default logger set to the DEBUG level. You can:

  1. Copy the provided logging.config file to the root of your project or anywhere in the PROPATH.
  2. If you already have a logging.config file in your project, you can add the logger configuration from the provided file into your existing logging.config, or write your own.

Example Configuration

Below is an example of the logger configuration you can include in your logging.config file:

{
"logger": {
"[package]": {
"logLevel": "DEBUG",
"filters": [
"ERROR_FORMAT",
"FULL_TEXT_FORMAT",
{
"name": "NAMED_FILE_WRITER",
"fileName": "[package]_${t.today}.log",
"appendTo": true
}
]
}
}
}

Multiple Project Configuration

If you have multiple projects using this library, you can configure separate logging for each:

{
"logger": {
"[package]": {
"logLevel": "DEBUG",
"filters": [
{
"name": "NAMED_FILE_WRITER",
"fileName": "[package]_${t.today}.log",
"appendTo": true
}
]
},
"[package].Apis": {
"logLevel": "INFO",
"filters": [
{
"name": "NAMED_FILE_WRITER",
"fileName": "[package]-apis_${t.today}.log",
"appendTo": true
}
]
},
"[package].Models": {
"logLevel": "WARN",
"filters": [
{
"name": "NAMED_FILE_WRITER",
"fileName": "[package]-models_${t.today}.log",
"appendTo": true
}
]
}
}
}

Advanced Logging Options

Currently, each class that uses logging will use its own namespace + class name as logger, meaning that you can enable specific logging for a single Api class, Model.

Example: If you want to log all Api classes in a separate file, add an extra logger with the namespace [package].Apis

{
"logger": {
...,
"[package].Apis": {
"logLevel": "DEBUG",
"filters": [
"ERROR_FORMAT",
"FULL_TEXT_FORMAT",
{
"name": "NAMED_FILE_WRITER",
"fileName": "[package]-Apis_${t.today}.log",
"appendTo": true
}
]
}
}
}

For more information about the logging.config and filter options, refer to the official documentation:

8. Documentation for API Endpoints

Detailed API endpoint documentation will be available when docs generation is re-enabled in a future version. For now, refer to the generated API classes in the [package].Apis package.

Available Endpoints:

  • GET /orders - Retrieve a list of orders (via OrdersApi:GetOrders())

  • POST /orders - Create a new order (via OrdersApi:PostOrders())

  • GET /orders/{orderId} - Retrieve an order by ID (via OrdersApi:GetOrdersByOrderId())

  • PUT /orders/{orderId} - Update an existing order (via OrdersApi:PutOrdersByOrderId())

  • DELETE /orders/{orderId} - Delete an order (via OrdersApi:DeleteOrdersByOrderId())

9. Documentation for Models

Detailed model documentation will be available when docs generation is re-enabled in a future version. For now, refer to the generated model classes in the [package].Models package.

10. Documentation for Authorization

Documentation for authorization will be provided in a future version.