Operations

In cases where you need to use API methods (other than CRUD introduced in the resource model overview), all of them must be specified as operations (custom operations) in the corresponding APS type definition.

Introduction

Let us suppose an application has a service that can perform a calculation-intensive operation, and you need to expose it. This can be declared in the type definition as follows:

"operations": {
   "calculateSomething": {
       "path": "/calculateSomething/{paramX}",
       "verb": "GET",

       "response": {
            "type": "string"  // Some JSON-schema that describes the response
       },

       "parameters": {
           "paramX": { "kind": "path", "type": "string" },
           "paramA": { "kind": "query", "type": "integer" },
           "paramB": { "kind": "query", "type": "integer" }
       }
   }
}

To invoke the operation with parameters paramX="special", paramA=1, paramB=2, the GET request will look as follows:

GET /aps/2/resources/<id>/calculateSomething/special?paramA=1&paramB=2

When you call a custom operation of a singleton platform service, you can use a shorter request format based on the service alias, for example:

GET /aps/2/services/order-manager/orders?

On receiving such a request, the APS controller identifies the application endpoint URL (<endpoint>) and the application service (<service>) that must process the operation, and then calls the application method as follows:

GET <endpoint>/<service>/<id>/calculateSomething/special?paramA=1&paramB=2

As shown in the above example, each operation includes a number of attributes, such as name, path, and verb.

Base CRUD Operations

The base CRUD operations - provision, retrieve, configure, and unprovision - are defined similarly in the Resource APS type and implemented by all other APS types. For example, the retrieve operation is defined as follows:

"retrieve": {
   "name": "retrieve",
   "verb": "GET",
   "path": "/"
}

In accordance with this definition, the following table presents examples of incoming REST requests for all four CRUD operations.

Name

APS controller

Application

provision

POST /aps/2/resources/
{JSON object}
POST /<endpoint>/<service>/
{JSON object}

Get resource

GET /aps/2/resources/<id>

-

retrieve

APS controller initiates request

GET /<endpoint>/<service>/<id>

configure

PUT /aps/2/resources/<id>
{JSON object}
PUT /<endpoint>/<service>/<id>
{JSON object}

unprovision

DELETE /aps/2/resources/<id>

DELETE /<endpoint>/<service>/<id>

In the APS infrastructure, base CRUD operations are processed as presented in the following diagram.

../../../../_images/operation-crud.png

The APS controller processes internally a base CRUD request, and then, except for the GET (retrieve operation) request, calls the corresponding method of the application. There is no need to call the retrieve operation, since all needed data is stored in the APS database.

Note

Since the APS controller processes an operation internally, the caller must have access to all of the following involved objects: the operation, the resource, and the property. Otherwise, it returns an error code.

The APS controller calls the retrieve operation periodically on the APS resources that have Resource Counters.

Custom Operations

When a custom operation is required, the APS proxy service calls the corresponding application method without internal processing.

../../../../_images/operation-custom.png

Note

Since the APS controller does not process the operation internally, the caller must have access only to the resource and the operation. Otherwise, it returns an error code. The called operation is processed by the application. The latter has unlimited permissions to its resources.

Operation Attributes

The full list of operation attributes is presented in the table:

Attribute

Value

Required?

Default

Example

name

string

Yes

N/A

“calculateSomething” in the above example

path

string

Yes

N/A

“path”: “/calculateSomething/{paramX}”

verb

- GET
- PUT
- POST
- DELETE

Yes

N/A

“verb”: “GET”

response

* JSON primitive
* JSON object
* APS type
* MIME type

Yes

N/A

“response”: { “type”: “string”}

“response”: { “contentType”: “image/jpeg”}

errorResponse

JSON object

Yes

N/A

“errorResponse”: {
“type”: “object”,
“properties”: {
“code”: “integer”,
“error”: “string”,
“message”: “string”
}
}

parameters

JSON object

-

null

“parameters”: {
“param_name_1”: { “kind”: “path”, “type”: “string” },
“param_name_2”: { “kind”: “query”, “type”: “long” }
}

static

boolean

-

false

“static”: true

access

JSON object

-

N/A

“access”: { “referrer”: false }

name

Value: string
Default: N/A
Method name is used in documentation and code generation. In the above example, the operation name is “calculateSomething”.

path

Value: string
Default: N/A
This attribute defines a path (relative to the resource instance root), which corresponds to the operation. It is possible to define parameters in the URL. In this case, names of the parameters must be presented in the path and embraced in {}, like: “{paramX}” in the above example.

Limitations

  1. The path value must be a string starting with a letter and containing letters, numbers, and underscores. That is, it must match the regular expression [a-zA-Z][0-9a-zA-Z_]*.

  2. There should not be two operations that declare the same verb and path.

  3. An operation cannot have a path that matches a relation name, for example, there must not be a path “/ves” if we have a relation “ves”.

verb

Value: GET, POST, PUT, or DELETE
Default: null
Defines an HTTP method required to invoke the operation. See RFC-2616-sec9 for a detailed description of these standard methods.

response

Value: JSON object or MIME type
Default: null
response can be specified as a valid JSON schema, just like any entry in a structure including:

The following example shows how a declaration of the “string” type response would look like:

{
    "response": {
        "type": "string"
    }
}

Note

It is possible to refer to any type declared in the Structures section.

It is possible to declare a non-JSON format as a response. To do that, the contentType attribute that contains a declaration of a valid MIME Media Type RFC-2046 must be used. An example of a method that returns image/jpeg data is:

{
   "response": {
       "contentType": "image/jpeg"
   }
}

Warning

Simultaneous usage of the contentType and type attributes is not supported and will produce an error, because if the type is specified, the proper MIME type is assigned automatically.

errorResponse

Value: JSON object
Default: null
errorResponse works like the response element, but declares the return format that will be used in case of method failure. This is an example of the error structure:
{
    "errorResponse": {
        "type": "object",
        "properties": {
            "code": "long",
            "error": "string",
            "message": "string"
        }
    }
}

Note

It is NOT possible to declare a contentType element in the errorResponse.

parameters

Value: JSON object
Default: null
Parameters describe the input data passed to the called operation. They are defined as follows:
{
   "parameters": {
       "arg1": {
           "kind": "query",
           "type": "integer",
           "required": true
       },
       "arg2": {
           "kind": "body",
           "type": "MyType",
           "required": true
       }
   }
}

The parameters section may be empty if the operation does not require any parameters. A declared parameter can have the following attributes:

  • name uniquely identifies the parameter.

    {
       "parameters": {
         "param_name_1": { /* details */ },
         "param_name_2": { /* details */ },
         "param_name_3": { /* details */ }
        }
    }
    

    The name is explicitly sent in the URI if the kind attribute of the parameter is query.

  • kind specifies the way a parameter is passed to the application. It may be either path, query, or body:

    • path - the parameter is passed in the path part of the URL. Only the Primitives are supported.

    • query - the name and value of the parameter are passed as a query argument in the URL. Only the Primitives are supported.

    • body - the parameter is passed in the request body and can be a JSON object as defined in Structures or an object of any MIME Media Type .

    Warning

    Only one parameter of kind body is allowed per custom operation.

  • A declaration of the parameter type is done using either the type or contentType attribute:

    • type declares whether the parameter must be one of the Primitives (if the path or query kind) or refers to one of Structures (if the body kind) that defines the parameter format.

    • contentType requires the body kind and is used to declare non-JSON content. The attribute must declare a valid MIME Media Type. An example of a method that receives image/jpeg data in the HTTP body is as follows:

      "parameters": {
          "image": {
               "kind": "body",
               "contentType": "image/jpeg",
               "required": true
          }
      }
      

    Warning

    Simultaneous usage of the contentType and type attributes is not supported and will produce an error since the type attribute implicitly declares the application/json MIME type.

  • required is an optional attribute that defines whether the parameter is mandatory (true) for the operation or optional (false). The default value is false.

static

Value: boolean
Default: false
Defines the base URL that will be used for calling the operation. By default, the value is false, which means that the operation URL is relative to the resource base URL. In the following examples, the URL for the resource called “collection” is {base}/collection/. With the "static":false definition
{
   "verb": "GET",
   "path": "/test"
   /* "static" is "false" by default */
}

the operation must be called using this URL:

GET {base}/collection/{ID}/test

If static is set to true, the operation URL is relative to the “collection” URL:

{
    "verb": "GET",
    "path": "/test",
    "static": "true"
}

Which means:

GET {base}/collection/test

Such a declaration allows for defining methods specific to the “collection”. For example, when a resource is created by the base provision operation, there is no resource ID yet, and therefore the operation is declared as static in the APS core resource schema.

access

Value: JSON object
Default: N/A
Allows or disallows access to the operation for different Security Roles. With the following definition, a referrer cannot run the start operation:
"operations": {
    "start": {
        "verb": "GET",
        "path": "/start",
        "response": {
            "contentType": "text/json",
            "type": "string",
            "items": null
        },
        "access": { "referrer": false }
    },
    ...
}

Examples

In the following examples, we will demonstrate how to use parameters of all three kinds : path, query, and body.

Sending JSON Object in Body

This example illustrates how to send a JSON object in HTTP body.

  • First, let us create a JSON schema for a parameter that will be passed in the body:

    "structures": {
        "MyType": {
           "type": "object",
           "properties": {
              "param1": {
                 "type": "string"
              },
              "param2": {
                 "type": "integer"
              }
           }
        }
    }
    
  • Now, we can define an operation with parameters of different kinds:

    "operations": {
        "calculateSomething": {
           "path": "/calculateSomething/{paramX}",
           "verb": "POST",
           "response": {"type": "string"},
           "parameters": {
               "paramX": { "kind": "path", "type": "string" },
               "paramA": { "kind": "query", "type": "integer" },
               "paramB": { "kind": "query", "type": "integer" },
               "bodyC":   { "kind": "body", "type": "MyType" }
           }
        }
    }
    
  • REST requests will send the first three parameters in the URI, while the forth parameter (JSON structure containing param1 and param2) will be sent in the message body as follows:

    POST /aps/2/resources/{ID}/calculateSomething/special?paramA=1&paramB=2
    Content-Length: 123
    Content-type: application/json
    
    {
        "param1" : "Testing parameter sent in body",
        "param2" : 1024
    }
    

Sending Arbitrary Contents in Body

This example illustrates how to declare and then send a non-JSON object, for example, plain text.

  • The operation is defined as:

    "operations": {
        "calculateSomething": {
           "path": "/calculateSomething/{paramX}",
           "verb": "POST",
           "response": {"type": "string"},
           "parameters": {
               "paramX":        { "kind": "path", "type": "string" },
               "paramA":        { "kind": "query", "type": "integer" },
               "paramB":        { "kind": "query", "type": "integer" },
               "description":   { "kind": "body", "contentType": "text/plain" }
           }
        }
    }
    
  • REST requests look as follows:

    POST /aps/2/resources/{ID}/calculateSomething/special?paramA=1&paramB=2
    Content-Length: 3237
    Content-type: text/plain
    
    Description of parameters:
    o paramX presents...
    

Custom Filters

A custom operation can process its own custom filters that are specified in the REST request URL.

Note

Although the filter request format in URL is arbitrary, we recommend using the format of Resource Query Language to be compliant with the standard RQL filters used for various purposes.

The APS controller does not verify custom operation syntax and forwards a request to a custom operation to the APS application endpoint as is.

For example, a custom operation orders can select orders passing the criteria specified in a request. The following is a request for the SO and BO orders created earlier than the specified time-stamp and whose status is COMPLETED.

GET /aps/2/services/order-manager/orders?in(type,(SO,PO)),in(status,(COMPLETED)),le(creationDate,1518607046)

Limitations

In REST requests containing a payload, the latter must not exceed 10 MB.