OIH Standard Library
Table of Contents
Actions
Upsert Object
For implementing UpsertObject action in most cases you need to extend from UpsertObjectById
or UpsertObjectByUniqueCriteria
classes and following methods:
lookupObject(criteria: any, objectType: any, cfg?: any, msg?: any)
createObject(object, cfg, msg)
updateObject(criteria: any, objectType: any, object: any, cfg?: any, msg?: any)
If you need completely custom behaviour you can extend from Upsert
class and override process
, in this case following OIH standard is your responsibility.
Note:
- Its your responsibility to ensure that
lookupObject
returns only 1 object. lookupObject
method must return null
to indicate that object hasn't been found.
Upsert Object By Id
- Create Action
- Create class that extends
UpsertObjectById
class - Implement
lookupObject()
,createObject()
,updateObject()
methods. Example below. - Optional override methods:
getType
- default implementation expects objectType
to be present in input configuration,getCriteria
- by default, returns id
value from body in input message or null,getObjectFromMessage
- by default, returns body
object from input message.
- Create instance of your class and pass
logger
to constructor. const myUpsertObjectByIDImpl = new MyUpsertObjectByIdImpl(logger);
- Export
myUpsertObjectByIDImpl.process(msg, cfg, snapshot)
as process method. Example below.
Example of Usage
Works in sailor > 2.4.2
Upsert Object Action
const { UpsertObjectById } = require('@elastic.io/oih-standard-library/lib/actions/upsert');
class MyUpsertObjectByIdImpl extends UpsertObjectById {
async lookupObject(criteria, objectType, cfg, msg) {
const existObject = await getObjectInAPI(criteria, objectType, cfg, msg);
if (existObject) { return existObject; }
return null;
}
async createObject(object, cfg, msg) {
return await createObjectInAPI(object, cfg, msg);
}
async updateObject(criteria, objectType, object, cfg, msg) {
return await updateObjectInAPI(criteria, objectType, object, cfg, msg);
}
}
async function process(msg, cfg, snapshot = {}) {
const upsertAction = new MyUpsertObjectByIdImpl(this.logger);
return upsertAction.process(msg, cfg, snapshot);
}
module.exports.process = process;
Upsert By Unique Criteria
The same as Upsert Object By Id but getCriteria
method by default returns value of field uniqueCriteria
that is defined in input configuration, from the body in the input message.
Create Object
Similar to upsert object but needed for the following cases:
- Objects that can be created but can not be updated after creation (e.g. Invoices)
- Cases where you want to create an object and its children
- Cases where the id of the object includes information in the object (e.g. The ID of a sales line is the sales order ID + SKU).
Example Use Case
See above.
Lookup Object (at most 1)
For implementing LookupObject action in most cases you need to extend from LookupObjectById
or LookupObjectByUniqueCriteria
classes.
If you need completely custom behaviour you can extend from LookupObject
class and override process and lookupObject method,
in this case following OIH standard is your responsibility.
Lookup Object By Id
Note:
- Its your responsibility to ensure that
lookupObject
returns only 1 object. This implementation assume that id
is unique for objectType
. lookupObject
method must return null
to indicate that object hasn't been found.
- Create Action
- Create class that extends LookupObjectById class
- Override
lookupObject()
methods. Example below. - Optional override
getType
and getId
methods. Default implementation expects objectType
to be present in input configuration and id
in input message. - Create instance of your class and pass
logger
to constructor. const myLookupByIDImpl = new MyLookupByIdImpl(logger);
- Export
myLookupByIDImpl.process(msg, cfg, snapshot)
as process method. Example below.
Example of Usage
Works in sailor > 2.4.2
Lookup Action
const { LookupById } = require('@elastic.io/oih-standard-library/lib/actions/lookupObject');
class MyLookupByIDImpl extends LookupById {
async lookupObject(id, objectType, cfg, msg) {
const result = await lookupObjectInAPI(id, objectType, cfg, msg);
return result;
}
}
async function process(msg, cfg, snapshot = {}) {
const lookupAction = new MyLookupByIDImpl(this.logger);
return lookupAction.process(msg, cfg, snapshot);
}
module.exports.process = process;
Lookup Object By Unique Criteria
Note:
- In case when
lookupObject
method has found more than 1 object it must return an array or throw error. lookupObject
method must return null
to indicate that object hasn't been found.
- Create Action
- Create class that extends LookupObjectByUniqueCriteria class
- Override
lookupObject()
methods. Example below. - Optional override
getType
and getCriteria
methods. Default implementation expects objectType
to be present in input configuration and id
in input message. - Create instance of your class and pass
logger
to constructor. const myLookupObjectByUniqueCriteriaImpl = new MyLookupObjectByUniqueCriteriaImpl(logger);
- Export
myLookupObjectByUniqueCriteriaImpl.process(msg, cfg, snapshot)
as process method. Example below.
Example of Usage
Works in sailor > 2.4.2
Lookup Action
const { LookupByUniqueCriteria } = require('@elastic.io/oih-standard-library/lib/actions/lookupObject');
class MyLookupObjectByUniqueCriteriaImpl extends LookupByUniqueCriteria {
async lookupObject(criteria, objectType, cfg, msg) {
const result = await lookupObjectInAPI(id, objectType, cfg, msg);
if (result instanceof Array) {
}
return result;
}
}
async function process(msg, cfg, snapshot = {}) {
const lookupAction = new MyLookupObjectByUniqueCriteriaImpl(this.logger);
return lookupAction.process(msg, cfg, snapshot);
}
module.exports.process = process;
Lookup Objects (Plural)
For implementing Lookup Objects (plural), you will have to extend from LookupObjects
class.
You must provide the functions getObjectsByCriteria(objectType, criteria: Array, msg?, cfg?, pageSize?, firstPage?, orderBy?):
and getMetaModel(cfg)
Steps for implementation
- Create Action
- Create class that extends
LookupObjects (plural)
- Override
getObjectsByCriteria()
and getMetaModel()
- Optionally override methods like
getCriteria()
. Default implementation assumes a specific format to the metadata fields as provided by getInMetadata()
, so you may wish to also override this function - Create instance of your class and pass the
logger
method to the constructor. - Export
myLookupObjects.process(msg, cfg, snapshot)
as process method. Example below:
Example
const { LookupObjects } = require('@elastic.io/oih-standard-library/lib/actions/lookupObjects');
class MyLookupObjects extends LookupObjects {
async getObjectsByCriteria(objectType, criteria, msg, cfg) {
const results = await lookupObjects(objectType, criteria);
return results;
}
async getMetaModel(cfg) {
const metaModel = {};
const properties = {
fields: ['field1', 'field2'],
conditions: ['=', 'in'],
orderEnum: ['asc', 'desc'],
includeOrder: false,
additionalFields: 'additionalField',
criteriaLinkEnum: ['and', 'or'],
disableCriteriaLink: false
};
metaModel.in = this.getInMetadata(cfg, properties);
metaModel.out = {
type: object,
...
};
return metaModel;
}
}
async function process(msg, cfg, snapshot = {}) {
const deleteAction = new MyLookupObjects(this.logger, this.emit);
return deleteAction.process(msg, cfg, snapshot);
}
module.exports.process = process;
Delete Object
For implementing Delete action in most cases you need to extend from DeleteById
or DeleteByUniqueCriteria
classes.
If you need completely custom behaviour you can extend from Delete
class and override process and deleteObject method,
in this case following OIH standard is your responsibility.
Delete By ID
Note:
- Its your responsibility to ensure that deleteObject deletes only 1 object. This implementation assume that
id
is unique for objectType
. - If
deleteObject
method is returning null
empty object would be emitted. You can indicate with null
that object hasn`t been deleted or found.
- Create Action
- Create class that extends DeleteById class
- Override
deleteObject()
methods. Example below. - Optional override
getType
and getId
methods. Default implementation expects objectType
to be present in input configuration. For unique criteria: uniqueCriteria
field name in input configuration and value in input message. - Create instance of your class and pass
logger
to constructor. const myDeleteByIDImpl = new MyDeleteByIdImpl(logger);
- Export
myDeleteByIDImpl.process(msg, cfg, snapshot)
as process method. Example below.
Example of Usage
Works in sailor > 2.4.2
Delete Action
const { DeleteById } = require('@elastic.io/oih-standard-library/lib/actions/delete');
class MyDeleteByIDImpl extends DeleteById {
async deleteObject(id, cfg, msg) {
const deletedID = await deleteObjectInAPI(id, cfg, msg);
return deletedID;
}
}
async function process(msg, cfg, snapshot = {}) {
const deleteAction = new MyDeleteByIDImpl(this.logger);
return deleteAction.process(msg, cfg, snapshot);
}
module.exports.process = process;
Delete By Unique Criteria
Note:
- If more than 1 object was found with same uniqueCriteria, error would be thrown by this implementation
- If
deleteObject
method is returning null
empty object would be emitted. You can indicate with null
that object hasn`t been deleted or found.
- Create Action
- Create class that extends DeleteById class
- Override
findObjectByCriteria
and deleteObject()
methods. Example below. - Optional override
getType
and getCriteria
methods. Default implementation expects objectType
to be present in input configuration. For unique criteria: uniqueCriteria
field name in input configuration and value in input message. - Create instance of your class and pass
logger
to constructor. const myDeleteByCriteriaImpl = new MyDeleteByCriteriaImpl(logger);
- Export
myDeleteByCriteriaImpl.process(msg, cfg, snapshot)
as process method. Example below.
Example of Usage
Works in sailor > 2.4.2
Delete Action
const { DeleteByUniqueCriteria } = require('@elastic.io/oih-standard-library/lib/actions/delete');
class MyDeleteByCriteriaImpl extends DeleteByUniqueCriteria {
async findObjectByUniqueCriteria(criteria, type, cfg, msg) {
const object = await findObjectInAPI(criteria, type, cfg, msg);
const numberOfObjects = object.count;
return {
object,
numberOfObjects
}
}
async deleteObject(object, cfg, msg) {
const deletedID = await deleteObjectInAPI(object, cfg, msg);
return deletedID;
}
}
async function process(msg, cfg, snapshot = {}) {
const deleteAction = new MyDeleteByCriteriaImpl(this.logger);
return deleteAction.process(msg, cfg, snapshot);
}
module.exports.process = process;
Triggers
Get New And Updated Objects Polling
For implementing et New And Updated Objects Polling(Polling Trigger) extend from class PollingTrigger
and override: getObjects
, getObjectsFromPage
methods.
Note:
getObjectsFromPage(objectType, startTime, endTime, page, cfg)
- is expecting parameter page
. Page is structure with fields: pageNumber
, pageSize
, singlePagePerInterval
.getObjectsFromPage
- must return following structure: { 'objects': 'result of polling' 'nextPage' : 'number or object, represents next page to poll' }
.emitIndividually
behaviour expects array to be returned by method: getObjects
.- Its responsibility of implementation to handle situation when
startTime
> endTime
How to implement:
- Create Trigger
- Create class that extends
PollingTrigger
- Override
getObjects()
and getObjectsFromPage()
methods - Optionally override methods any other methods, see class
PollingTrigger
- Create instance of your class and pass the
logger
nad emitter
to the constructor. - Export
myPollingTrigger.process(cfg, snapshot)
as process method. Example below:
Example of Usage
const PollingTrigger = require('@elastic.io/oih-standard-library/lib/triggers/getNewAndUpdated');
class MyPollingTriggerImpl extends PollingTrigger {
async getObjects(objectType, startTime, endTime, cfg) {
return api.poll(objectType, startTime, endTime, cfg);
}
async getObjectsFromPage(objectType, startTime, endTime, page, cfg) {
const result = await api.pollPage(objectType, page, startTime, endTime, cfg);
return { nextPage: result.nextPage, objects: result.objects }
}
}
async function process(cfg, snapshot) {
const trigger = new MyPollingTriggerImpl(this.logger, this.emit);
return trigger.process(cfg, snapshot);
}
module.exports.process = process;
Webhooks
Firstly, Webhook subscription handling strategy should be implemented.
For this purpose HandleWebhookSubscriptionByIdAbstractStrategy
must be extended and createWebhooks
& deleteWebhooks
methods must be implemented.
Also can be defined absolutely new strategy. For this purpose, just implement interface HandleSWebhookSubscriptionAbstractStrategy
.
Example of Usage
const { HandleWebhookSubscriptionByIdAbstractStrategy, Webhook, defaultProcessWebhook } = require('@elastic.io/oih-standard-library/lib/triggers/webhook');
class HandleWebhookSubscriptionByIdStrategy extends HandleWebhookSubscriptionByIdAbstractStrategy {
constructor(client, logger) {
super(logger);
this.client = client;
}
async createWebhooks(objectType, eventTypes) {
const webhooks = await Promise.all(eventTypes.map(eventType => this.client.create({
topic: eventType,
address: process.env.ELASTICIO_FLOW_WEBHOOK_URI,
format: 'json',
}, WEBHOOK_OBJECT_TYPE)));
return { ids: webhooks.map(webhook => webhook.id) };
}
async deleteWebhooks(input) {
await Promise.all(input.ids.map(id => this.client.delete({ id }, WEBHOOK_OBJECT_TYPE)));
}
}
function configuredWebhook(cfg, logger) {
const credentials = {
apiKey: cfg.apiKey,
shopName: cfg.shopName,
password: cfg.password,
};
const client = new Client(credentials);
const handleWebhookSubscriptionByIdStrategy = new HandleWebhookSubscriptionByIdStrategy(client, logger);
const webhook = new Webhook(logger, handleWebhookSubscriptionByIdStrategy);
return webhook;
}
async function startup(cfg) {
const webhook = await configuredWebhook(cfg, this.logger);
return webhook.startup(cfg);
}
async function shutdown(cfg, data) {
const webhook = await configuredWebhook(cfg, this.logger);
await webhook.shutdown(cfg, data);
}
module.exports.process = defaultProcessWebhook;
module.exports.startup = startup;
module.exports.shutdown = shutdown;