Solution Framework Components
The local scope of the implementation class is accessed by using a reserved word
this
.
From here it is possible to access other components that are needed for the implementation such as input, output, repository, factory, util …etc.
For example:
// create ns1 entity
const entity1 = this.factory.entity.nsacrnm1.entityIdentifier();
// create ns2 entity
const entity2 = this.factory.entity.nsacrnm2.entityIdentifier();
These components are the following:
Input
Holds the values of each input property provided by the user. It is important to define the properties of the input entity in Solution Designer, otherwise they will not be accessible in the Action SDK.
// Access the value of the input property
const val = this.input.propertyName
Output
Contains the output properties and provides their value as output to the user. Before assigning values to the output properties one must initialize the type of the output entity.
// Initialize output via factory and assign value to output properties
this.output = this.factory.entity.nsacrnm.serviceIdentifier_Output();
this.output.property1 = ‘Some property value’;
Instance
Contains all the properties that belong to an instance of an entity (of all types). The properties that are contained in this component are editable.
// Edit instance property value
this.instance.property1 = ‘New property value’;
Entity Factory
This is used to create an entity object (of all types including input and output entities). If this is assigned to a variable, then the variable will contain all the properties and commands that belong to the specific entity. The properties of the variable are editable.
// Create an Entity using entity factory
const entity1 = this.factory.entity.nsacrnm.Entityidentifier();
// Access entity1 properties
entity1.propIdentifier = ‘some property value’;
Error Factory
This is used to create a new business error that can be thrown to the user.
// Create an error using error factory
const error1 = this.factory.error.nsacrnm.ErrorIdentifier();
// Access error1 properties
error1.errorDescription = ‘Some Error Description’;
error1.errorMessage = ‘Some Error Message;
Reference Factory
This is used to create a reference to an external entity or a root entity on the same or a different namespace inside the solution. If referencing external entities, this component calls the constructor and it returns the created instance of the external entity. If referencing other aggregates, it returns the instance that is being referenced. In both cases the returned values are read-only.
// Create an entity reference for root entity using reference factory
const ref1 = this.factory.reference.nsacrnm.RootEntityIdentifier(‘someEntityId);
// Load referenced entity
const rootEntity = await ref1.load();
// create a reference to an external entity that takes an input
// Create input object via factory
const input = this.factory.entity.cptest.ExternalEntityIdentifier_ConstInput();
input.propertyIdentifier = 'Some property value';
External Factory
This calls the constructor method of the external entity. It returns the local instance of the
external entity from which it is possible to access the associated properties as well as
call the load
and validate
methods.
// Create external entity reference
const extEntity = await this.factory.external.cptest.ExternalEntityIdentifier(input);
// Access the associated properties
extEntity.assProp1;
// Load external entity - no input needed
extEntity.load();
// Validate external or update local - no input needed
extEntity.validate();
Event Factory
This is used to create an event. It returns empty properties that belong to the payload and the publish function in order to trigger the event. The properties of the payload are editable. The properties and the values assigned to them will be the input of the agent that is called after triggering the event.
// Create an event using event factory
const event1 = this.factory.event.nsacrnm.EventIdentifier();
// create event payload using entity factory
const payoad = this.factory.entity.nsacrnm.EntityIdentifier();
// set payload properties
payload.propIdentifier = ‘some property value’;
// Set event payload
event1.payload = payoad;
// publish event
await event1.publish();
Schema Factory
This is used to create schema objects. It returns the properties that belong to the schema (i.e.
the entire schema object/array/oneOf). The properties returned are editable. This is
accessible from operation scripts and .test.ts
files of operations.
// Create a schema using schema factory
const schema1 = this.factory.schema.nsacrnm.SchemaIdentifier();
// Access schema1 properties
schema1.propIdentifier = ‘some property value’;
Repository
This is used to access the data-store of a solution and retrieve an existing instance of a root entity given an id or a filter. It is also possible to create a completely new root entity through this component by accessing the factory command. It returns the entity object (or an array of entity objects when searched by filter). From each entity object all the properties and instance commands linked to this entity are available. The returned values are read-only.
// Access the repository of the specific root entity and choose the find
// Find takes an object argument and a filter argument
// In the Find Configuration Object,
// The first one is a Boolean indicated whether all children should be included in the filtering (true) or not (false).
// The second is the limit (optional field) that takes string of a pair of numbers as a value where the first number is the <offset> and the second is the <amount> of entries that will be returned
// The third is the sortBy argument that takes a string of a pair where the first element is the local identifier of a property and the second is either ASC or DESC
const rootEntityInstance = this.repo.nsacrnm.RootEntityIdentifier.find(FindConfigurationObj, Filter);
//Example
const rootEntityInstance = this.repo.nsacrnm.RootEntityIdentifier.find({includeSubentities: true, limit: “2,20”, sortBy: “customerID,DESC”}, `name == "${name}"`);
// Find entity by id
const rootEntityInstance = this.repo.nsacrnm.RootEntityIdentifier. findById(`EntityId`);
Filter expressions
A more detailed description of filter expressions is available at Filter Expression
Services
This is used to call services that have been modelled and defined in one solution in Solution Designer. This returns the output of the service implementation.
// Initialize service input via factory and assign value to input properties
const input = this.factory.entity.nsacrnm.serviceIdentifier_Input();
input.property1 = ‘Some property value’;
// Create a service instance
const service1 = await this.services.nsacrnm.serviceIdentifier(input);
// Access service output
const val = service1.output.propIdentifier;
Solution metadata
It is possible to access the solution details for logging purposes by using the
this.solution
component.
const acrnm = this.solution.acronym;
const name = this.solution.name;
const category = this.solution.category;
The values in the this.solution
are read-only.
InstanceOf check
Entity Instance Check
In the implementation file of a service, command, agent and operation entity instance check can be done through isInstanceOf functionality, the entity instance check will also check for the entity hierarchy.
// check an object
if (this.isInstanceOf.entity.ns1.BlueCar(car)) {
// now one can access the special property that only blue car has
const prop = car.specialPropOfBlueCar;
}
// check BlueCar is a Car (Since BlueCar is a child of Car, the entity instance check will also check for the entity hierarchy)
if (this.isInstanceOf.entity.ns1.Car(blueCar)) {
// now one can access the special property that only car has
const prop = blueCar.specialPropOfCar;
}
Error Instance Check
In the implementation file of a service, command, agent and operation error instance check can be done by using isInstanceOf functionality, thus enable to code handling logic for different error instances
General Errors Checking
try {
// try some logic
} catch (e) {
// check for GeneralError
if (this.isInstanceOf.error.GeneralError(e)) {
// now can handle this general error
}
// check whether the validation of an entity (used as input or instance) fails
if (this.isInstanceOf.error.ValidationError(e)) {
// now can handle this validation error
// check for a child of abstract BusinessError
if (this.isInstanceOf.error.BusinessError(e)) {
// now can handle this Business error
}
// check whether an action (e.g. a command) is not currently available
if (this.isInstanceOf.error.ActionNotAvailableError(e)) {
// now can handle this ActionNotAvailable error
}
// check whether an aggregate is found in the datastore
if (this.isInstanceOf.error.AggregateNotFound(e)) {
// now can handle this AggregateNotFound error
}
// check whether an external request (i.e. this.util.request) caused an error
if (this.isInstanceOf.error.ExternalRequestError(e)) {
// now can handle this ExternalRequest error
}
// check whether an internal request caused an error
if (this.isInstanceOf.error.InternalRequestError(e)) {
// now can handle this InternalRequest error
}
}
Business Errors Checking
try {
// try some logic
} catch (e) {
// check whether the error matches any of the errors modelled in Solution Designer
if (this.isInstanceOf.businessError.ns1.NoBalanceAvailable(e)) {
// now can handle this specific business error
}
if (this.isInstanceOf.error.ValidationError(e)) {
// now can handle this validation error
}
if (this.isInstanceOf.businessError.ns2.NoCustomerFound(e)) {
// now can handle this specific business error
}
}
API Dependencies
As a precondition the API needs to be defined as an API dependency in an integration namespace and needs an Open API 3.0 or Swagger 2.0 specification. If this is given, the API could be called within the implementation of an integration service.
Call an operation of the API
// call operation "getPets" in integration API "petstore"
const result = await this.apis.petstore.getPets();
Call an operation with path parameters and query parameters
If path parameters or query parameters are defined, the function offers the possibility to set these parameters which are identified by the name. The values of the path parameters as well as the query parameters are expected to be JavaScript objects where each key is the name of the parameter. The URL and ca_certs are used automatically according to the specification.
// findPets by owner (pathParameter) and filter by status and age (queryParameter)
const result = await this.apis.petstore.getPetsOfOwner({
owner: 'MyOwner'
}, {
status: 'alive',
age: 5
});
Call an operation with request body
If a request body is defined for the operation, the function offers the possibility to set the request body as a JavaScript object.
// add new pet using "pet data" (request body)
await this.apis.petstore.addPet({
owner: 'MyOwner',
status: 'alive',
age: 1
});
Read result of operation
The result of the operation always consists of the status code and the actual response data. Both are returned from the operation call.
try {
const result = await this.apis.petstore.getPets();
// read result depending on status code
if (result.status === 200) {
// everything is good --> read data
const pets = result.data;
console.log(pets[0].status);
}
} catch (e) {
// handle error
this.util.log.error(e.message);
throw e;
}
API Binding
The value of the API Bindings is provided under this.apiBindings.APIIdentifier()
// get binding of petstore API
const bindingValue = await this.apiBindings.getPetstore();
Logging
This provides utility logging functions info,warn, error and debug.
// the log.error() can take an array of argumnets
this.util.log.error(‘Error Message’, errorObject);
// the log.debug() can take an array of argumnets
this.util.log.debug(‘Debug Message’, errorObject);
// the log.info() can take an array of argumnets
this.util.log.info(‘Info Message’, object);
// the log.warn() can take an array of argumnets
this.util.log.warn(‘Warning Message’, object);
Audit Logging
The Audit Logging services offers the transaction and performance logging functionality.
// the revlog.publish() can take an array of argumnets
this.util.revlog.publish(‘Audit Message’, Object);
Global Kafka consumers can be implemented to consume the Audit log messages and persist them in a secure data store.
HTTP Requests
To make an HTTP request against external APIs.
The this.util.request provides functions for the get,post,del,patch, and put HTTP operations.
const response = await this.util.request.get(url: string, queryParams?: HTTPQueryParams, head-ers?: HTTPHeaders, sslConfig?: SSLConfig);
OR
const response = await this.util.request.del(url: string, queryParams?: HTTPQueryParams, head-ers?: HTTPHeaders, sslConfig?: SSLConfig);
OR
const response = await this.util.request.patch(url: string, queryParams?: HTTPQueryParams, body?: any, headers?: HTTPHeaders, sslConfig?: SSLConfig);
OR
const response = await this.util.request.post(url: string, queryParams?: HTTPQueryParams, body?: any, headers?: HTTPHeaders, sslConfig?: SSLConfig);
OR
const response = await this.util.request.put(url: string, queryParams?: HTTPQueryParams, body?: any, headers?: HTTPHeaders, sslConfig?: SSLConfig);
Request Context
This provides information regarding the current request context the command is executed with.
// get request context via this._context
const requestContext = this._context.requestContext;
Request
This provides access to operation request it contains the below components.
Path
This is used to give access to the request path parameters of an operation.
// access operation request path parameters
const val = this.request.path.pathParamIdentifier;
Query
This is used to give access to the request query parameters of an operation.
// access operation request query parameters
const val = this.request.query.queryParamIdentifier;
Body
This is used to give access to the request body of an operation. If the request body is a simple type (i.e. integer, number, string etc) then the value is accessed immediately. Otherwise, in case the body is an object, the command is expanded to access each property. In case that the body is an array type, then the body can be treated similarly to a JavaScript Array.
// access operation request body
const body = this.request.body;
const val = this.request.body.popertyIdentifier;
Response
This provides access to operation request it contains the below components
Status
This is used to access the response status of an operation. The value only takes the values that have been modelled in the Solution Designer.
// set response status to be returned
this.response.status = 200;
// access operation response status
const status = this.response.status;
Body
This is used to access the response body of an operation to the user. If the body is a primitive type schema, then a value can be directly accessed / assigned. Otherwise, the body must be initialized to its corresponding schema type (using the schema factory component) and then each property should be initialized accordingly.
// initialize response body via schema factory
const body = this.factory.nsacrnm.schema.schemaIdentifier();
// set operation response body
this.response.body = body;
const val = this.response.body.popertyIdentifier;
Headers
This is used to access the values of the response headers of an operation.
// access operation request body
const headers = this.response.headers;
Install new module dependencies
In the solution, you can install two kind of dependencies: devDependencies and dependencies.
DevDependencies
Modules that are only needed for local development and testing.
Dependencies
Modules required by your application in production.
Install DevDependenices
In the solution directory, run the command npm install moduleName -D
Install Dependencies
In the solution directory, run the command npm install moduleName
Different scopes inside each implementation
Below is an Illustrative table for the different scopes inside each implementation element.
Service | Command | Agent | Operation | External Entity construct | External Entity load | External Entity validate | |
this.input | √ | √ | √ | √ | |||
this.output | √ | √ | √ | √ | √ | √ | |
this.instance |
|
√ | √ | √ | √ | ||
this.factory.entity | √ | √ | √ | √ | √ | √ | |
this.factory.error | √ | √ | √ | ||||
this.factory.reference | √ | √ | √ | ||||
this.factory.event | √ | √ | √ | ||||
this.factory.schemas | √ | ||||||
this.repo | √ | √ | √ | √ | √ | ||
this.services | √ | √ | √ | √ | √ | ||
this.util.log | √ | √ | √ | √ | √ | √ | √ |
this.util.revlog | √ | √ | √ | √ | √ | √ | √ |
this.request.path | √ | ||||||
this.request.query | √ | ||||||
this.request.body | √ | ||||||
this.response.headers | √ | ||||||
this.response.status | √ | ||||||
this.response.body | √ | ||||||
this.requestContext | √ | √ | √ | √ |