The Progress OpenEdge.Web.DataObjectHandler (DOH) is a built-in WebHandler class that enables you to design your own ABL service interface and expose ABL data objects as RESTful resources in a configurable way. It is available via the WEB transport in Progress Application Server for OpenEdge (PAS for OpenEdge).

If you have developed Progress ABL Data Object Services, you have already used the DOH under the hood.

How the DOH works

The DOH class implements the Progress.Web.IWebHandler interface, and is a more dynamic and business-ready form of the OpenEdge.Web.WebHandler class. With the DOH, you create an ABL service, set it to use the OpenEdge.Web.DataObjectHandler class, and then map custom service endpoints to ABL classes and procedures in a JSON mapping file.

At runtime, when a service endpoint is called, the DOH transforms the HTTP request into an ABL object and invokes the associated ABL class or procedure. It also transforms the output from the ABL class or procedure into an HTTP response.

Should I use a user-defined WebHandler, the DOH or a mapped REST service?

Although you can also define a custom service interface using a mapped REST service (that uses the PAS for OpenEdge REST transport) or a user-defined WebHandler, a DOH-based ABL service offers the following advantages over the mapped REST service:

  • It supports more content types.

  • It is easier to debug, since the DOH is an ABL class. You can also readily inspect and modify its JSON mapping file.

  • It is more customizable; you can extend its functionality by accessing its class events. To learn more about these class events, see the white paper on using the DataObjectHandler.

  • It uses the WEB transport, which is the recommended way to expose your ABL applications as RESTful services. This is because the WEB transport uses the ABL WebHandler class and thus provides better insight and control over your ABL service.

Overview of steps to use the DOH

  1. Create an ABL service — You begin by creating an ABL service that uses the DOH class.
  2. Create a mapping file — You then create a mapping file with the same name as the ABL service.
  3. Define custom service endpoints — You start describing the service interface in the mapping file by defining your custom endpoints.
  4. Associate HTTP verbs with operation handlers — For each service endpoint, you associate an HTTP verb (GET, PUT, POST, etc) with one of the following operation handlers:
    • void, that returns only a status code
    • file, that returns the contents of a file
    • entity, that invokes an ABL class or procedure

Create an ABL service

The first step is to create an ABL service that uses the DOH. Perform this task as follows:

  1. Right-click the root project name in the Project Explorer view in Progress Developer Studio and select New > ABL Service.
  2. Select WEB in the Transport dropdown.
  3. Enter a name for the service, (such as HelloService).
  4. In the WebHandler section, choose Select existing and then browse and select OpenEdge.Web.DataObject.DataObjectHandler.
  5. Add a single resource URI that matches the service name (/HelloService).
  6. Click Finish.

Create a mapping file

After creating a DOH-based ABL service, you describe its service interface in JSON in a mapping file with the extension .map. The DOH uses this mapping file to execute the service's operations. If a client application attempts to call an endpoint or service that is not described in the mapping file, the DOH returns a 404 (Not Found) error.

Create a new text file in your ABL web app project's /PASOEContent/WEB-INF/openedge folder with the same name as the ABL service and with the extension .map (for example, HelloService.map). The matching filename instructs the DOH to use the mapping file for the service's operations. Placing it in the “openedge” folder makes it discoverable in the application PROPATH.

At minimum, you need to define a single service within a services object. Like this:

{    "services":
      {
        "HelloService": {           
        "version": "1.0.0"       
      }
    }
 }

The service name must match the ABL service and resource URI name that you set while creating the ABL service. The “version” property defines the version of the service and should follow the Semantic Versioning pattern (for example,. “1.0.0”). The JSON snippet, as shown in this example, provides just enough to make the service discoverable but does not do much else. Without this minimum configuration, the server would only return an HTTP-404 response for the service.

Define custom service endpoints

In the JSON mapping file, define custom service endpoints under an operations object. For example:

{
	"services": {
		"HelloService": {
			"version": "1.0.0",
			"operations": {
				"/Greeting": {},
				"/Message": {},
				"/": {}
			}
		}
	}
}
This registers the endpoints with the DOH class and makes them accessible as REST resources. Client applications access these resources using the full endpoint URI. For example:
  • http://localhost/CustomerApp/web/HelloService/Greeting
  • http://localhost/CustomerApp/web/HelloService/Message

Associate HTTP verbs with operation handlers

For each custom service endpoint, you associate HTTP verbs with operation handlers. You can set up operation handlers for all HTTP verbs that are supported by the WEB transport. These include:
  • GET
  • PUT
  • POST
  • DELETE
  • HEAD
  • OPTIONS
  • TRACE
  • PATCH

Specify each verb that you want to use as a JSON object under the service endpoint in the mapping file. For example:

{
	"services": {
		"HelloService": {
			"version": "1.0.0",
			"operations": {
				"/Greeting": {
					"GET": {},
					"PUT": {},
					"POST": {}
				},
				"/Message": {
					"GET": {},
					"PUT": {}
				},
				"/": {
					"GET": {}
				}
			}
		}
	}
}
Content types

Within each verb, define the MIME content type of the data that is returned by the endpoint. For example:

"/Greeting": {
	"GET": {
		"contentType": "application/json"
	}
}

All MIME types (text/, image/, audio/, video/, application/, multipart/) are supported.

Status codes
In addition to the content type, define the status code that is returned by the endpoint. For example:
"/Greeting": {
	"GET": {
		"contentType": "application/json",
		"statusCode": 200
	}
}
Operation handlers

Next, map each HTTP verb with one operation handler. The DOH class provides the following operation handlers:

  • void, that returns only a status code
  • file, that returns the contents of a file
  • entity, that invokes an ABL class or procedure

To map an HTTP verb with an operation handler, nest the operation handler under the verb as shown in this example:

"/Greeting": {
	"GET": {
		"contentType": "application/json",
		"entity": {}
	},
	"PUT": {
		"contentType": "application/json",
		"entity": {}
	}
}
"/Message": {
	"GET": {
		"contentType": "application/json",
		"file": "filepath"
	}
}
"/": {
	"GET": {
		"contentType": "application/json",
		"void": null
	}
}
The file and void operation handlers are simple key-value pairs whereas the entity handler is a JSON object. This is because the entity handler requires further information (such as the ABL class or procedure name, the method that will be invoked, etc).