Open API development

The Open API specification (previously known as Swagger) plays an important role in IBM BPM interactions with external systems. In order to be fully proficient in BPM, you also need to have a grounding in Open API.

To cut immediately to its core, Open API is to REST requests what WSDL is to Web Service requests using SOAP over HTTP. Open API allows us to describe the nature of a target REST service. Given that description, we can then unambiguously determine how to invoke the target service.

An instance of an Open API service description is a JSON document. It can be written directly in JSON or written in YAML which can be translated to JSON.

Here is an example core of an Open API document:

swagger: '2.0'
info:
  x-ibm-name: sample
  title: Sample
  version: 1.0.0
schemes:
  - https
host: www.example.com
basePath: /sample
consumes:
  - application/json
produces:
  - application/json
securityDefinitions:
  basic-1:
    type: basic
    description: Basic Authentication
security:
  - basic-1: []
paths: {}
definitions: {}
tags: []

Let us look at some of the core parts.

The first is the "schemes" entry. This describes which protocol we will use to invoke the service. These include "http" and "https".

The "host" entry defines the host name used as the target of the service request.

The "basePath" specifies the base part of the URL used to target a REST request.

For example, imagine we had a REST request that could be targeted by a GET request to:

http://www.example.com/sensorData/temperature

The host would be "www.example.com", the basePath would be "/sensorData" and the remainder of the URL ("/temperature") would be the path used to define a specific operation.

Now let us look at the "paths" entries. It is here we define the paths relative to the basePath that define endpoints for service requests. The "paths" entry is an object where each property of the object defines a local relative path:

paths:
	"/pathA":
      <definition for PathA>
	"/pathB":
      <definition for PathB>
   …

This would say that there are endpoints for service requests at:

http://<host>/<basePath>/pathA

and

http://<host>/<basePath>/pathB

A REST request requires not just where we are sending the request but also with method we are at that endpoint. The methods are:

  • get
  • put
  • post
  • delete
  • … others

What this means is that for every endpoint, we must then define which methods we are supporting. For example:

paths:
	"/pathA":
      get:
         <definition of get request>
      put:
         <definition of put request>
      …

For a given endpoint and method, we next define what the parameters are for that method:

paths:
	"/pathA":
      put:
         parameters:
         - name: param1
           <Parameter definition>
         - name: param2
           <Parameter definition>
         …

An individual parameter is composed of:

  • name – The logical name of the parameter.
  • description – An optional description of the parameter.
  • type – The data type of the parameter.
  • required – Whether the parameter is required or not.
  • in – How the parameter is supplied in a request. Our choices are:
    • query – The parameter will be supplied in the query part of the request.
    • body – The parameter will be supplied in the body of the request.
    • path – The parameter will be encoded in the path of the request.
    • header – The parameter will be set in the HTTP header of the request.

Examples:

paths:
  '/test':
    get:
      summary: Summary
      description: Description
      parameters:
      -  name: param1
         type: string
         in: query

When the "in" value is "body", we are declaring that we are passing the parameters of the operation as payload in the request. When we specify this option, we must also specify the schema.

JSON Schema

The JSON Schema is a description of how a document encoded in JSON could be validated. It can also be used to provide a template for the construction of a valid JSON document. The JSON Schema notation is itself described in JSON.

For example:

{
   "type": "object",
   "properties": {
      "name": {
         "type": "string"
      }
      "age": {
         "type": "number"
      }
   }
}

would describe a JSON object that could contain:

{
   "name": "Neil",
   "age": 96
}

The "type" keyword defines the allowable types. These are:

  • string
  • object
  • array
  • boolean
  • null
  • number
    • integer

When the "type" is "object", then we must supply a "properties" object which contains the properties contained within that object.

For example, imagine an address as containing a house number, street and city, then we might define:

"address": {
   "type": "object",
   "properties": {
      "houseNumber": { "type": "integer" },
      "street": { "type": "string" },
      "city": { "type": "string" }
   }
}

Thus the following would be an example:

{
   "houseNumber": 12
   "street": "elm street",
   "city": "Dallas"
}

But what if there are additional properties in the JSON instance … for example:

{
   "houseNumber": 12
   "street": "elm street",
   "city": "Dallas",
   "state": "TX"
}

The "state" property is not defined in the schema. By default, additional properties beyond those defined are allowed and will pass validation. If we wish, we can restrict the JSON validation to be only the defined properties by adding:

"additionalProperties": false

In the schema definition. For example:

"address": {
   "type": "object",
   "properties": {
      "houseNumber": { "type": "integer" },
      "street": { "type": "string" },
      "city": { "type": "string" }
   },
   "additionalProperties": false
}

What about omitted properties. For example, will the following parse?

{
   "houseNumber": 12
   "city": "Dallas"
}

It doesn't include a "street" property. By default, the answer is yes it will. If we wish, we can define the set of properties which must be supplied for an instance to be valid. We do this with the "required" array.

"address": {
   "type": "object",
   "properties": {
      "houseNumber": { "type": "integer" },
      "street": { "type": "string" },
      "city": { "type": "string" }
   },
   "required": ["houseNumber", "street", "city"],
   "additionalProperties": false
}

When working with arrays, we specify the "type" as "array". When we do this, we must also specify the content of the array with object called "items" that contains a type specifier within it.

See also:

The Open API editors

While it is perfectly possible to construct and edit an Open API document in a text editor, there are a number of excellent editors available that are aware of the Open API specification and provide entry assist and other related tools.

The swagger.io editor

The Swagger Editor is found at the swagger.io web site. This provides a browser hosted editor that is easy to use:

In the left pane we see the document that describes the Open API document and on the right, a testing environment for executions. The entry of the document description has to be performed by hand and there is no guidance on what to do next nor a higher level map as is found in some other editors. Entry assistance seems satisfactory. In addition to running on-line, we can also download it for local execution. For local execution it runs under Node.js.

When making requests to BPM, we have to be concerned about CORS. The Swagger editor is loaded from https://editor.swagger.io/ but yet wants to form a REST request to your BPM server and is thus prevented. One solution is to launch Chrome in development mode using:

$ chrome --disable-web-security --user-data-dir

This will disable all security so be careful. You may also wish to try and manually enter a URL to obtain SSL certificates for the first request.

See also:

Eclipse – Kaizen-openepi-editor

A common platform in which to perform development tasks is Eclipse. Eclipse doesn't natively understand OpenAPI but with the help of some open source plugins, it can. An excellent example of such is the "KaiZen OpenAPI Editor".

See also:


Revision #1
Created 2 years ago by Admin
Updated 2 years ago by Admin