Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The support for invoking Business Tasks and Business Entity Methods through the RESTful interface is based on the requirements described in this article: RESTful services. Particularly the RestEntitiesWebHandler and the RestResourceService (as an Service a Service Instance of the IRestResourceService). 

Business Task methods and Business Entity methods are exposed as RESTful resources using the same set of annotations - and actually share a lot of similaritysimilarities. Business Entity invokable methods are typically PUBLIC VOID methods with a ProDataset INPUT-OUTPUT parameter and a (JSON serializable) parameter object. Business Task methods are typically PUBLIC VOID methods with zero to five ProDataset INPUT-OUTPUT parameters and a (JSON serializable) parameter object. 

Info
titleSupport for return value of Business Task and Business Entity Methods

Also to facilitate the support for RESTful invocation of Business Task and Business Entity methods the Consultingwerk.OERA.ServiceInterface:InvokeTask API has been enhanced with support for returning the return value of a method to the caller. This finally allows developers to separate the request message from the response message.

The InvokeTask API is fully capable of invoking Business Entity methods as well.

...

Due to limitations of the ABL reflection API, we currently do not support ProDatasets passed as the input to Business Task and Business Entity methods. This limitation has been accepted in our design process as we expect a majority of use-cases for RESTful invocation of Business Task and Business Entity methods just requires to return data in ProDatasets, not to receive data. So, the only input message to the invokable messages supported through the RESTful interface is the parameter object instance. 

As ABL reflection is not capable of providing the schema of the ProDataset parameters we've had to balance the requirement to provide the schema of the ProDataset parameters manually (through code in the Business Tasks) with the ease of use. The schema of ProDataset parameters is required as the loosely typed JSON messages do not allow the AVM to securely create an input ProDataset "on the fly" without losing schema compatibility with strong the strongly typed Dataset's used within Business Tasks and Business Entities. 

Preparing

...

Business Tasks and Entities for RESTful invocation of methods

Business Tasks

A Business Task needs to implement the ISupportsRestMethods interface in order to support RESTful invocation. This Interface is expected by the IRestResourceService.

...

RESTful interfaces for Business Entity methods are defined by an @RestMethod a @RestMethod annotations attached to the method (just before the METHOD block). 

...

The annotation provides the following arguments:

AgumentArgument/AttributeMandatoryDescription
addressnoThe URI pattern to invoke the method. When not specified the pattern /{methodName} is used by default
ParameterClassNamenoThe name of the parameter class to instantiate for calling into the method. When not specified, we will pass an unknown value (?) to the method.
RequestMethodnoThe http method for the call described by this annotation. When not specified, get will be assumed as the default.
ResponseyesComma delimited list of the components for the JSON response of the REST request. Components are "return" and the names of the ProDataset parameters are the name of the parameter object.

Every invokable methods method may be annotated with more than a single @RestMethod annotation to provide alternative URI's for the same method.

Population of the Parameter object

The REST request to the annotated method will be used to populate the properties of the method's parameter object using the following sources:

...

Arguments of the @ParameterSchema annotation

When Business Task methods are configured to return a Dataset as the method response, it's required to provide an XSD file with the ProDataset schema to be included in the method documentation, e.g.:

Argument/AttributeMandatoryDescription
datasetnameyes

The name of the dataset

schemafileyes

The path reference to the dataset schema

The @ParameterSchema annotation is optional. 

Population of the Parameter object

The REST request to the annotated method will be used to populate the properties of the method's parameter object using the following sources:

  1. For GET requests, the query string is first parsed and query string values will be used to populate the same named properties of the parameter object
  2. For all other request methods, e.g. POST, the request entity (request payload) .  

Population of the JSON response of the request

The JSON response object can either be populated by the return value of the method alone or a combination of the return value, the parameter object and the ProDataset parameter(s). For the return value we support both Consultingwerk.JsonSerializable derived types and JsonObjects/JsonArrays. For the parameter object we only support JsonSerializable instances. 

Examples

Classic invokable method of a Business Entity

...

languagec#

...

  1. - when the request entity represents a JSON object - is used to deserialize a JSON serializable parameter object.
  2. For all request methods (GET, POST, ...), the path parameter arguments are also assigned to properties of the parameter object. This is performed at the end, so that path parameters, as the strongest component of the request URI, overwrite properties assigned by query string components or deserialized form the request entity (request payload).  

Population of the JSON response of the request

The JSON response object can either be populated by the return value of the method alone or a combination of the return value, the parameter object and the ProDataset parameter(s). For the return value we support both Consultingwerk.JsonSerializable derived types and JsonObjects/JsonArrays. For the parameter object we only support JsonSerializable instances. 

Examples

Classic invokable method of a Business Entity

Code Block
languagec#
    @RestMethod (address="/Customers/~{CustNum}/PutCustomerOnHold", requestMethod="get", parameterClassName="Consultingwerk.SmartComponentsDemo.OERA.Sports2000.PutOnHoldParameter", response="dsCustomer").
    /*------------------------------------------------------------------------------
        Purpose: Puts the Customer on hold
        Notes:   Client callable method
        @param dsCustomer INPUT-OUTPUT DATASET
        @param poParameter The Parameter Object for this method
    ------------------------------------------------------------------------------*/
    METHOD PUBLIC VOID PutCustomerOnHold (INPUT-OUTPUT DATASET dsCustomer,
                                          poParameter AS PutOnHoldParameter):

...

This annotation defines an endpoint for a Business Task method that will be exposed using a GET request under an URI llike like this:

http://localhost:8820/web/Entities/CalculateSumTask?Value1=17&Value2=4

The method parameter object properties are populated from the two values in the query string.  The request will return the serialized DecimalHolder instance:

Code Block
languagejs
{
  "Value": 21.0
}

The same method can also be exposed like this:

Code Block
languagec#
{
  "Value": 21.0
}

The same method can also be exposed like this:

Code Block
languagec#
    @RestMethod (address="/CalculateSumTask/~{value1}/~{value2}", requestMethod="get",
                 parameterClassName="Consultingwerk.SmartComponentsDemo.OERA.CalculateSumParameter",
                 response="return").
    METHOD PUBLIC DecimalHolder CalculateSum (poParameter AS CalculateSumParameter):

http://localhost:8820/web/Entities/CalculateSumTask2/47/11

Business Task method returning two ProDatasets and optionally the parameter object

Code Block
languagec#
    @RestMethod (address="/GetCustomerAndInvoices", requestMethod="get",
                 parameterClassName="Consultingwerk.IntegerHolder",
                 response="poParameter,dsCustomer,dsInvoice").
    @RestMethod (address="/GetCustomerAndInvoices/~{Value}", requestMethod="get",
                 parameterClassName="Consultingwerk.IntegerHolder",
                 response="dsCustomer,dsInvoice").
    @RestMethod (address="/CalculateSumTask/~{value1}/~{value2}GetCustomerAndInvoices", requestMethod="get",post",
                 parameterClassName="Consultingwerk.IntegerHolder",
                 response="dsCustomer,dsInvoice").
    @ParameterSchema   parameterClassName(datasetname="dsCustomer", schemafile="Consultingwerk./SmartComponentsDemo./OERA/Sports2000/dsCustomer.CalculateSumParameterxsd",).
    @ParameterSchema (datasetname="dsInvoice", schemafile="Consultingwerk/SmartComponentsDemo/OERA/Sports2000/dsInvoice.xsd").
    METHOD PUBLIC VOID GetCustomerAndInvoices (INPUT-OUTPUT  response="return").DATASET dsCustomer,
    METHOD PUBLIC DecimalHolder CalculateSum (poParameter AS CalculateSumParameter):

http://localhost:8820/web/Entities/CalculateSumTask2/47/11

Business Task method returning two ProDatasets and optionally the parameter object

Code Block
languagec#
    @RestMethod (address="/GetCustomerAndInvoices", requestMethod="get",                  parameterClassName="Consultingwerk.IntegerHolder",             INPUT-OUTPUT DATASET dsInvoice,
  response="poParameter,dsCustomer,dsInvoice").     @RestMethod (address="/GetCustomerAndInvoices/~{Value}", requestMethod="get",                     parameterClassName="Consultingwerk.IntegerHolder",                  response="dsCustomer,dsInvoice").
    @RestMethod (address="/GetCustomerAndInvoices", requestMethod="post",
poParameter AS IntegerHolder):

This method allows clients to provide the Value property of the IntegerHolder parameter in one of three ways:

GET http://localhost:8820/web/Entities/GetCustomerAndInvoices?Value=1

GET http://localhost:8820/web/Entities/GetCustomerAndInvoices/1

POST http://localhost:8820/web/Entities/GetCustomerAndInvoices with a JSON payload like: 

Code Block
languagejs
"poParameter": {
    "Value": 1
  },
"dsCustomer": {
     parameterClassName="Consultingwerk.IntegerHolder",
"eCustomer": [
    {
		"CustNum":           response="dsCustomer,dsInvoice").
    METHOD PUBLIC VOID GetCustomerAndInvoices (INPUT-OUTPUT DATASET dsCustomer,
                                               INPUT-OUTPUT DATASET dsInvoice,
                                               poParameter AS IntegerHolder):

This method allows to provide the Value property of the IntegerHolder parameter in one of the three ways:

GET http://localhost:8820/web/Entities/GetCustomerAndInvoices?Value=1

GET http://localhost:8820/web/Entities/GetCustomerAndInvoices/1

POST http://localhost:8820/web/Entities/GetCustomerAndInvoices with a JSON payload like: 

Code Block
languagejs
{ "Value": 21,
		"Country": "USA",
		"Name": "Lift Line Skiing",
		"Address": "Unter Käster 1",
		"Address2": null,
		"City": "Chicago",
		"State": "MA",
		"PostalCode": "01730",
		"Contact": "Gloria Shepley",
		"Phone": "(617) 450-0086",
		"SalesRep": "HXM",
		"CreditLimit": 0,
		"Balance": 50000,
		"Terms": "PREPAID ONLY",
		"Discount": 35,
		"Comments": "Put on hold: 25.06.2019 07:46:59\ntest",
		"Fax": "",
		"EmailAddress": "info@lift-tours.com",
		"Flags": "C",
		"SmartRecordKey": "000000001",
		"SmartAttachments": true,
		"SmartComments": false,
		"SmartCopiedFrom": ""
	}
  ]
},
"dsInvoice": {
  "eInvoice": [
	{
	"Invoicenum": 6,
	"CustNum": 1,
	"InvoiceDate": "2009-02-09",
	"Amount": 1829.5,
	"TotalPaid": 1829.5,
	"Adjustment": 0,
	"OrderNum": 6,
	"ShipCharge": 0
	},
	{
	"Invoicenum": 79,
	"CustNum": 1,
	"InvoiceDate": "2008-11-19",
	"Amount": 34707.84,
	"TotalPaid": 34707.84,
	"Adjustment": 0,
	"OrderNum": 79,
	"ShipCharge": 0
	},
	{
	"Invoicenum": 146,
	"CustNum": 1,
	"InvoiceDate": "2009-02-28",
	"Amount": 4605.91,
	"TotalPaid": 0,
	"Adjustment": 0,
	"OrderNum": 177,
	"ShipCharge": 0
	}
  ]
}