[Update for ORDS 22+] Plugin Example – Get YAML response for ORDS services

My previous example for adding a YAML filter to ORDS service responses no longer applies with ORDS 22.1.0 and later. In the past the approach for extending the ORDS functionality was to modify the distributed ords.war with a plugin jar. Now there is a separate lib/ext/ directory for extension jars. This post will revisit last year’s Plugin Example – Get YAML response for ORDS services and cover what is different now. The end goal will still be to have YAML returned for an AutoREST table rather than JSON.

ORDS 22.3.3 will be used. Available from https://oracle.com/rest

JSON and YAML

My client ‘Accepts’ YAML

As mentioned in the previous post, when an ORDS service is created, by rest enabling a table for example, the default content type for requests and response payloads is application/json. The end goal for this exercise is to convert any application/json response to a text/yaml response without having to modify the service implementation. The client specifies that YAML should be returned by stating that text/yaml is acceptable…

curl -i -H "Accepts: text/yaml" http://localhost:8080/ords/hr/employees/

…which gets this response

HTTP/1.1 200 OK
Content-Type: text/yaml
ETag: "v7RO6F9A6fwTqkJvp28hXrluD1r31Uo4stahc5jCzCPtXKk8ke8S0cEcmED1FqOT2PdZ/VkEqgREVjTp2sWptA=="
Transfer-Encoding: chunked

---
items:
- employee_id: 100
  first_name: "Steven"
  last_name: "King"
  email: "SKING"
  phone_number: "515.123.4567"
  hire_date: "1987-06-16T23:00:00Z"
  job_id: "AD_PRES"
  salary: 24000
  commission_pct: null
  manager_id: null
  department_id: 90
  links:
  - rel: "self"
    href: "http://localhost:8080/ords/hr/employees/100"
...removed for brevity...

hasMore: true
limit: 25offset: 0
count: 25
links:
- rel: "self"
  href: "http://localhost:8080/ords/hr/employees/"
...removed for brevity...

ORDS Custom Plugin

To achieve this we will code our own custom plugin to ORDS. The ORDS distribution from oracle.com/rest contains example plugins and for simplicity one of these examples will be copied as the basis of our new custom plugin. First I’ll provide the code and steps to build the plugin. Then I will go through the plugin code to explain key parts.

Assumptions and prerequisites

This example is based on the plugin examples in the ORDS Getting Started tutorial. It is assumed that you are already familiar with that plugin-demo Servlet example.

We’re using ORDS 22.3.3 with Oracle Java 11 in standalone mode. A configuration directory has already been created containing valid connection details to a database that has ORDS installed. There is a REST Enabled schema in the database with a REST Enabled table that does not require authentication to access. In my example the schema is HR, the table is EMPLOYEES and the RESTful endpoint is http://localhost:8080/ords/hr/employees.

ORDS 22.3.3 ships with Jackson which will be the basis for the YAML conversation of the JSON response. However, other jars will be required at compile and runtime.

In this article I will refer to the new plugin as plugin-yaml but you can use any name that suits.

  1. Copy the examples/plugins/plugins-demo directory to examples/plugins/plugin-yaml
  2. Change the project name in the build.xml to plugin-yaml
    • <project default=”dist” name=”plugin-yaml”>
  3. Remove the examples/plugins/plugin-yaml/src/example/PluginDemo.java
  4. Download PluginYaml.java to examples/plugins/plugin-yaml/src/example/
  5. Download jackson-core-2.13.0.jar to examples/plugins/plugin-yaml/lib/
  6. Download jackson-databind-2.13.0.jar to examples/plugins/plugin-yaml/lib/
  7. Download jackson-dataformat-yaml-2.13.0.jar to examples/plugins/plugin-yaml/lib/
  8. Download snakeyaml-1.28.jar to examples/plugins/plugin-yaml/lib/
  9. Open a command shell at the examples/plugins/plugin-yaml/ directory
  10. At the command line run ant

So far, all the steps have been the same as for last year’s example. Now, instead of adding the jars to the ords.war we add them to the existing lib/ext/ directory where ORDS has been installed.

  1. Copy the following files to ORDS home lib/ext/ directory:
    • built/plugin-yaml.jar
    • lib/jackson-dataformat-yaml-2.13.0.jar
    • lib/snakeyaml-1.28.jar
  2. Start ORDS: ords –config /path/to/config/ serve
  3. Send a request for JSON data: curl -i http://localhost:8080/ords/hr/employees/
  4. Send a request for YAML data: curl -i -H “Accepts: text/yaml” http://localhost:8080/ords/hr/employees/

Review of the artefacts

There are 3 jars to add to the lib/ext/ directory to be picked up in the ORDS classpath at runtime in. The plugin-yaml.jar which we have built from source and the 2 runtime dependencies jackson-dataform-yaml and snakeyaml. Any subsequent code changes in examples/plugins/plugin-yaml/src/ will require the ant project to be built again but only the produced plugin-yaml.jar must be added to the lib/ext/ directory again.

Example output from running ant command:

Buildfile: /scratch/ords-22.3.3.311.1929/examples/plugins/plugin-yaml/build.xml

clean:
   [delete] Deleting directory /scratch/ords-22.3.3.311.1929/examples/plugins/plugin-yaml/built

compile:
    [mkdir] Created dir: /scratch/ords-22.3.3.311.1929/examples/plugins/plugin-yaml/built/classes
    [javac] Compiling 1 source file to /scratch/ords-22.3.3.311.1929/examples/plugins/plugin-yaml/built/classes
    [javac] Note: Discovered type annotated with @Provides: example.PluginYaml

dist:
      [jar] Building jar: /scratch/ords-22.3.3.311.1929/examples/plugins/plugin-yaml/built/plugin-yaml.jar

BUILD SUCCESSFUL
Total time: 0 seconds

Code Overview

The PluginYaml.java is a basic javax.servlet.Filter implementation that replaces the response output stream when the servlet container is about to return that response to the calling client. To achieve this, when it is determined that the client provides Accepts: text/yaml in the request, the filter supplies a HttpServletResponseWrapper which captures the original response. That wrapper, in this case called ServletResponseWrapperCopier, uses Jackson mappers to produce a YAML representation of the JSON response content and return that instead.

In summary, the filter…

Terms and Conditions

The performance overhead of producing a response in one structure and creating a copy of it in a different structure may be quite significant for large payloads. Although ORDS provides a plugin framework for you to add functionality, your custom plugin, or any third party jars that you add to the lib/ext/ are not supported by Oracle. The upshot is obvious. When it comes to plugins: test , test , test.

What about Tomcat and WebLogic?

The astute reader will have noticed that if the distributed ords.war is no longer modified then the additional jars will not be in the classpath of the ORDS web application when deployed to Apache Tomcat or Oracle WebLogic Server. That is where the ords war command comes in. Use the ords war command to create a deployable web application archive file which has the config.url context parameter explicitly set and any jar files from lib/ext folder are included.