REST Swagger File Reference Format

The descriptor for a REST service is a JSON file that contains information about the API and its data structure. The K2 REST broker uses this descriptor to communicate with the REST service, whether that's a service you own or one available on the Internet. This JSON file may be referenced either as a local file or an HTTP URL.

There are different ways to get a Swagger file for using with the REST broker, listed here in order of recommendation:

  1. Use the Swashbuckle package to generate a Swagger descriptor file. See https://community.nintex.com/k2-blackpearl-38/how-to-generate-a-swagger-descriptor-for-rest-based-services-using-swashbuckle-28534 for details on how to do this. This is the recommended approach if you own the API and can modify the source code.
  2. Ask the person who owns the API to generate a Swagger file for you.
  3. Use RESTUnited to generate a Swagger file based on the payload of the service. See https://community.nintex.com/k2-blackpearl-38/generating-a-swagger-descriptor-for-rest-based-services-using-restunited-com-28535 for details on how to do this. This is the recommended approach if you do NOT own the API. However, this approach typically requires that you to edit the Swagger descriptor to flatten entities.
  4. Generate a Swagger file manually. This is the least desirable approach as it requires extensive knowledge of the Swagger schema for the REST broker, JSON formatting, and knowledge of the API. However, this approach remains feasible if it is your only option. It is best to start with known Swagger descriptor files. See https://community.nintex.com/automation-on-prem-43/resources-for-working-with-the-rest-service-broker-93 for more information.

The REST broker supports portions of the Swagger v2 specification. For details about which elements are supported, see the Swagger Support Matrix.

Anatomy of a Swagger file

Field Description
host Name of the server hosting the REST service. (e.g. www.example.com)
basePath The root path to the API operations (e.g. /api/v2)
schemes The REST Broker currently only supports http and https
paths This is explained in more detail in the section below
definitions Defines the object entities used by the service. Each entity defined here will be represented as a SmartObject in K2

Paths

The paths portion of a Swagger file describes the URL paths, relative to the host and basePath previously defined, that the service provides. The path string may include path template tokens, which will be replaced with parameter values as described below.

Paths in the swagger file must be unencoded. Encoded paths will be re-encoded and this will break the URL.

Example paths:

"/pets" : {
    "get": { ... },
    "post": { ... },
},
"/order/{id}" : {
    "get": { ... },
}

Paths MUST begin with a slash (/).

Each path contains one or more operation nodes. An operation represents an HTTP verb or action. Swagger 2.0 supports seven operations; the current version of the REST Broker supports the following five:

"get": { ... },
"post": { ... },
"put": { ... },
"delete": { ... },
"patch": { ... },

Each path can define only one of each operation type. For example, a path cannot define two get operations. If you are describing a service that exposes two GET calls for the same path try appending an extraneous query parameter to make Swagger see it as a different path:

"/pets" : {
    "get": { ... },
},
"/pets?brokerWorkaround=ignoreMe" : {
    "get": { ... },
},

OperationId (method name)

By convention, the operationId property is used to provide a friendly name for the operation. The REST Broker uses this value for the Method name. If no operationId is provided in the descriptor, the broker will attempt to construct a method name from the path and operation type (e.g. get, post, delete)

"paths": {
    "/customers": {
        "get": {
            "operationId": "GetAllCustomers",
            ...,
        },
    }
}

Parameters

In Swagger, the body of the HTTP request and headers as well as form, query and URL parameters are all described as parameters of the operation:

{
    "in": "path",
    "name": "id",
    "required": true,
    "type": "integer"
},
{
    "in": "body",
    "name": "body",
    "required": true,
    "schema": { "$ref": "#/definitions/Pet" }
}

The type of parameter is noted by the in property, which can be any of the following:

  • path
  • query
  • body
  • file
  • header

The current version of the REST Broker supports all of these EXCEPT header.

The first example above defines a parameter that is passed as part of the path itself. A path template token with the same name is expected to be in the path definition:

"paths": {
    "/order/{id}" : {
        "get": {
            "parameters": [
                {
                    "in": "path",
                    "name": "id",
                    "required": true,
                    "type": "integer"
                }
            ]
        }
    }
}

The same technique can be used for query parameters. Body parameters define the contents of the main body of the HTTP request. File parameters are described below.

A few rules about parameters (for more, see the Swagger documentation on parameters):

  • Parameters in path MUST be required.
  • Parameters in body MUST provide a value for schema. (Other parameters MUST define a type.)
  • The "header" value for in is not currently supported by the REST Broker.

File Parameters

Swagger only supports describing file uploads using a multi-part form POST. For detailed information, see the Swagger documentation on parameters. For information about getting files from a service, see Handling Files in the Response

The following example outlines the basics for defining a file upload parameter:

"get": {
    "consumes": [
        "application/x-www-form-urlencoded"
    ],
    "parameters": [
        {
            "in": "formData",
            "name": "file",
            "required": true,
            "type": "file"
        }
    ]
}

The rules for file parameters are as follows:

  • MUST be in formData
  • consumes MUST be one of the following values:
    • application/x-www-form-urlencoded
    • multipart/form-data

Responses

Each Swagger operation MUST include at least one response definition, and should include the response for a successful call. Each response consists of the relevant HTTP Status Code - or the keyword default - and the defining Response Object:

"post": {
    ...,
    "responses": {
        "201": {
            "description": "Customer created (ID returned)",
            "schema": { "type": "integer" }
        },
        "400": {
            "description": "Invalid Customer data"
        },
        "default": {
            "description": "Unexpected error (detail included)",
            "schema": { "type": "string" }
        }
    }
}

The REST Broker determines what it considers to be the "success" response - the response it expects to receive from the operation - using the following logic:

  • The lowest 2xx HTTP Status Code present.1.
  • The default response, if present.2.
  • The first response in the list.3.
  • If no responses are found, the broker will not expect a response value from the operation.

Any other response that occurs is handled as an error.

Definitions

All complex entities used or returned by the API should be defined in the Swagger definitions section. The REST Broker creates a SmartObject for each entity described.

Swagger DOES NOT support the following:

  • Defining complex objects elsewhere in the descriptor (e.g. in a Response object). Such objects must be defined here and then referenced using $ref.
  • Inline definitions: Meaning that if an entity contains a property of another entity type you must declare each entity separately and then reference them for nesting purposes.
  • It may be necessary to define an object to hold the response that is actually not part of the response model. See When to Use a Root Object for more information.

Example:

"definitions" : {
    "Customer": {
        properties: {
            "ID": { "type": "integer" },
            "Active": { "type": "boolean" },
            ...
        }
    },
    "Order": {
        properties: {
            "ID": { "type": "number" },
            "Customer": {
                "$ref": "#/definitions/Customer"
            },
            "Date": {
                "type": "string",
                "format": "date-time"
            },
            ...
        },
    },
}

Each entity is defined by its name (i.e. "Customer" highlighted above) followed by a JSON Schema object.

Swagger strays from the JSON Schema specification for the following properties:

  • allOf - used to implement a simple inheritance. NOT CURRENTLY SUPPORTED by the REST Broker.
  • additionalProperties - defines a map, or dictionary, of dynamic properties. NOT CURRENTLY SUPPORTED by the REST Broker.

Handling Files in the Response

If the service you are calling returns a file (such as a PDF or Word document), you cannot directly map the returned file to a SmartObject property of type “File”. Instead, any unsupported or unrecognized type is mapped to a SmartObject property of type “Object” (Memo behind the scene), and then you can use the Get File from Content inline function to decode the file contents.

K2 Swagger Extensions

In order to integrate smoothly with K2 technologies the REST Broker recognizes the following extensions to the Swagger specification:

Extension Swagger Element Description
x-k2-displayName Schema Defines a friendly name to display to the end-user

Example:

"userTypeCustomer": {
    "properties": {
        "Name": {
            "schema": { "type": "string" }
        },
        ...
    },
    "x-k2-displayName": "User (Customer)"
}

Extension Swagger Element Description
x-k2-entityName Operation Specifies which entity (i.e. SmartObject) the operation (i.e. method) should be attached to

Example:

"paths": {
    "/orders?for={id}": {
        "get": {
            "operationId": "CustomerOrders",
            ...,
            "x-k2-entityName": "Customer"
        },
    }
},
"definitions": {
    "Customer": {
    ...
    }
}

Resolving Validation or Namespace Errors

If you see validation or namespace errors when trying to register your instance, it may mean that the Swagger file defintions section contains nested objects. The REST broker does not work with nested complex entities of the object type. For example, the category of the Pet object references the definition of category:

"Pet" : {
    "type" : "object",
    "required" : ["name", "photoUrls"],
    "properties" : {
        "id" : {
            "type" : "integer",
            "format" : "int64"
        },
        "category" : {
            "$ref" : "#/definitions/Category"
        },
        "name" : {
            "type" : "string",
        },
        ...

The category entity is defined separately (as a sibling of Pet) as its own object. Simple types are properties of an object, but object types must be defined separately and referenced.

"Category" : {
    "type" : "object",
    "properties" : {
        "id" : {
            "type" : "integer",
            "format" : "int64"
            ...

Dynamic Bindings

The REST broker supports static constructs, which means that if the objects returned by the service vary from call to call, the REST broker cannot work with those objects.

Dynamic API URI bindings: Some services implement load balancing by requiring a call to establish a session and, as a result of that call, you get a base URI to be used for all subsequent calls. Salesforce and Eloqua are examples of these services. The Swagger spec partially supports this construct at the time of publication but it isn’t defined enough for the REST broker to work with.

Dynamic Property Name bindings: Some services implement dynamic property names, where calls to the same endpoint result in the same payload structure but the names of the properties change with every call. The Swagger spec partially supports this construct at the time of publication but it isn’t defined enough for the REST broker to work with.

When to Use a Root Object

Sometimes it is necessary to create a root object to hold the contents of the returned objects.

For example, the following structure is returned by a service:

{
    "result": [
        {
            "sys_name": "SLA Repair Log Entry0004",
            "sys_class_name": "sys_db_object"
        },
        {
            "sys_name": "Dscy Priv Command Affinity",
            "sys_class_name": "sys_db_object"
        },
        {
            "sys_name": "Sys Plugins",
            "sys_class_name": "sys_db_object"
        },
        {
            "sys_name": "Alm Fixed Assets",
            "sys_class_name": "sys_db_object"
        },
        {
            "sys_name": "CMDB CI Server",
            "sys_class_name": "sys_db_object"
        }
    ]
}

The result object is not an array but it contains an array of strings. Creating a root object is necessary for the service to serialize and deserialize properly. To do this, first create an entity called rootObject that includes a reference to your result object and is an array object, as follows:

"rootObject": {
    "type": "object",
    "properties": {
        "result": {
            "type": "array",
            "items": {
                "$ref": "#/definitions/result"
            }
        }
    }
},

Use a reference to this rootObject in your method response, as follows:

"responses": {
    "200": {
        "description": "OK",
        "schema": {
            "$ref": "#/definitions/rootObject"
        }
    }
}

Finally, for your result object, specify the properties of type string that are parsed from the array:

"result": {
    "type":"object",
    "description": "Model for Result",
    "properties": {
        "sys_class_name": {
            "type": "string"
        },
        "sys_name": {
            "type": "string"
        }
    }
}