In cases, when 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.
In this document:
Let us suppose an application has a service that is able to 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¶mB=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¶mB=2
As shown in the above example, each operation includes a number of attributes, such as name
, path
, and verb
.
The base CRUD operations, correspondingly provision, retrieve, configure, and unprovision, are defined similarly in the APS core resource schema 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.
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.
When a custom operation is required, the APS proxy service calls the corresponding application method without internal processing.
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.
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 } |
Value: stringDefault: N/AMethod name is used in documentation and code generation. In the above example, the operation name is “calculateSomething”.
Value: stringDefault: N/AThis 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.
- 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_]*.
- There should not be two operations that declare the same path/method.
- An operation cannot have a path that matches a relation name, for example, there should not be a path “/ves” if we have a relation “ves”.
Value: GET, POST, PUT, or DELETEDefault:null
Defines an HTTP method required to invoke the operation. See RFC-2616-sec9 for the detailed description of these standard methods.
Value: JSON object or MIME typeDefault:null
response
can be specified as a valid JSON schema, just like any entry in a structure including:
- JSON primitive, that is “string”, “integer”, or another primitive
- JSON object defined by a structure
- JSON object defined by an APS type ID, for example “http://aps-demo.org/samples/basic/vps/1.0”
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
andtype
attributes is not supported and will produce an error, because if thetype
is specified, the proper MIME type is assigned automatically.
Value: JSON objectDefault:null
errorResponse
works like theresponse
element, but declares the return format that will be used in case of method failure. An example of an error structure may look like:{ "errorResponse": { "type": "object", "properties": { "code": "long", "error": "string", "message": "string" } } }Note
It is NOT possible to declare a
contentType
element in theerrorResponse
.
Value: JSON objectDefault:null
Parameters describe 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 isquery
.
kind
specifies the way a parameter is passed to the application. It may be eitherpath
,query
, orbody
:
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 is 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
orcontentType
attribute:
type
declares if the parameter must be one of the Primitives (in case ofpath
orquery
kind) or refers to one of Structures (in case ofbody
kind) that defines the parameter format.
contentType
requires thebody
kind and is used to declare non-JSON contents. 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
andtype
attributes is not supported and will produce an error since thetype
attribute implicitly declares the application/json MIME type.
required
is an optional attribute that defines if the parameter is mandatory (true
) for the operation or optional (false
). The default value isfalse
.
Value: booleanDefault:false
Defines the base URL that will be used for calling the operation. By default, the value isfalse
, 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}/testIf
static
is set totrue
, the operation URL is relative to the “collection” URL:{ "verb": "GET", "path": "/test", "static": "true" }means:
GET {base}/collection/testSuch a declaration allows defining methods specific for 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 asstatic
in the APS core resource schema.
Value: JSON objectDefault: N/AAllows 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 } }, ... }
In the following examples, we will demonstrate how to use parameters of all three kinds : path
, query
, and 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¶mB=2
Content-Length: 123
Content-type: application/json
{
"param1" : "Testing parameter sent in body",
"param2" : 1024
}
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 may look as follows:
POST /aps/2/resources/{ID}/calculateSomething/special?paramA=1¶mB=2
Content-Length: 3237
Content-type: text/plain
Description of parameters:
o paramX presents...
A custom operation can process its own custom filters specified in the REST request URL.
Note
Although the filter request format in URL is arbitrary, it is recommended to use the format of Resource Query Language to keep compliance 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)