-
Notifications
You must be signed in to change notification settings - Fork 0
Channel and Service Implementation
The channel and service implementation is the means by which the mACM Message Mediator is able to communicate with external messaging systems such as Twilio and Clickatell. The component supports a pluggable architecture to simplify the process of implementing new channels and services. The component relies on the configuration file (config.json) and data coming through from the "CommunicationRequest.channel" extension of the CommunicationRequest resource to know which channel and service to use.
A channel is a representation of a message delivery mechanism, examples include SMS, WhatsApp, App notifications, and many more. A channel can have one or many services. The component also has a default "channel" to support services that might not easily fit into one category.
New channels can be added by creating a folder under the /src/channels folder with the name of the channel and then implementing the following IChannel interface in an index.ts within this folder.
export interface IChannel {
/**
* Transform a CommunicationRequest into an object that conforms to INotificationRequest interface
*
* @param {CommunicationRequest} communicationRequest
* @return {INotificationRequest}
*/
createNotificationRequest (communicationRequest: CommunicationRequest, props: Object, extensions: Object[])
: INotificationRequest;
}
A service, on the other hand, is the actual implementation that communicates with an external messaging service such as Nexmo. A service can be thought of as an adapter/proxy for communicating with external messaging services.
New services can be added by extending the abstract MessagingInterface interface below in a file named according to the service name, in the /src/ folder. Note that the processStatusRequest method should be overridden if the status of a message must be fetched from the external service.
export abstract class MessagingService {
/**
* Processes a INotificationRequest and sends an alert/notification.
*
* @param {INotificationRequest} notificationRequest
* @return {Promise<CommunicationResource>}
*/
abstract processNotification(notificationRequest: INotificationRequest) : Promise<INotificationResponse>;
/**
* Processes an API callback from the implemented messaging service.
*
* @param {any} data
* @returns {Promise<CommunicationResource>}
*/
abstract processWebhook(data: any) : Promise<IWebhookResponse>;
/**
* Processes a request for the delivery status of an alert/notification.
* NOTE: This is an implementation of the IHE mACM profile transaction ITI-85
*
* @param {string} communicationRequestId
* @returns {Promise<CommunicationResource>}
*/
processStatusRequest(resource: ResourceType, params: Object)
: Promise<any> {
return new Promise((resolve, reject) => {
const fhirStoreUrl = buildHearthUrl({
host: config.get(EnvKeys.HearthHost) as string,
port: config.get(EnvKeys.HearthPort) as PortNumber,
secured: config.get(EnvKeys.HearthSecured) as boolean,
path: `fhir/${resource}`
});
fhirStore
.searchForResources(fhirStoreUrl, params)
.then(resolve)
.catch(reject);
});
}
Example
{
"url": "Communicaiton.channel",
"valueString": "sms:twilio"
}
Field | Value | Description |
url | Communicaiton.channel | The url field describes the extension to be used as defined in the FHIR specification. This field is required and must be set to "Communication.channel" |
valueString | [channel]:[service] | This field describes the data type and value of the extension. In our case, the value must be a string containing the channel and service name separated by a colon. |
{
"channels": {
"webhook": {
"host": "<host>",
"protocol": "http",
"port": 80
},
"metadata": [
{
"type": "sms",
"default": true,
"services": [
{
"default": true,
"name": "twilio",
"props": {
"token": "<token>",
"sid": "<sid>",
"from": "<from>",
"webhookActive": true
}
},
{
"name": "clickatell",
"props": {
"clickatellApiKey": "<clickatellApiKey>",
"url": "https://platform.clickatell.com/messages/http/send"
}
}
]
},
{
"type": "other",
"default": true,
"services": [
{
"name": "rapidpro",
"props": {
"flowApiUrl": "",
"token": "",
"flow": ""
}
}
]
}
]
}
Field | Constraint | Description |
webhook | optional | Used to specify the host to be used by service that need to send message delivery status updates via webhooks. |
webhook.host | required | The host address to be used for the webhook, this address could be any valid domain name or IP address. |
webhook.protocol | required | The HTTP protocol to used, this should be "Http" or “Https” |
webhook.port | optional | The port number to be used. The service will default to port 80 when this value is not specified. |
metadata | required | The metadata field is used to configure all channels and services. This field must contain at least one channel with at least one service. |
metadata.type | required | The identifier for the channel, there values here could be “sms”, “whatsapp”, “other”, or any other new channel being defined. |
metadata.default | optional | Specifies whether this channel is to be used as the default channel or not. Channels are used as default channels when the CommunicationRequest resource does not specify the channel in the “CommunicaitonRequest.channel” extension. |
metadata.services | required | Defines a collection of services for the channel. |
metadata.service.default | optional | Specifies when this service is to be used as the default service or not. Services are used as default services when CommunicationRequest resource does not specify the channel or service in the “CommunicationRequest.channel” extension. |
metadata.service.name | required | This is the name of the service and must match the name of the module implementing the service. The name is case-sensitive as it used to match module names in the code. |
metadata.service.props | optional | The component allows extra data to be passed to services via “props”. Props are extra fields required by the service and accessible via the message service interface. |