11. Message Type Helpers¶
The AMPS JavaScript client includes a set of helper
classes to make working with AMPS easier. The provided static
TypeHelper
class is used for fine grained control over message
types. It is also used for creating and parsing composite message types.
By default, the client supports the following message types:
- JSON;
- FIX / NVFIX - via
FixTypeHelper
class; - Binary;
- Composite types built from the combinations of the above types.
Messages of these types are automatically parsed into native JavaScript data structures and are ready for consumption.
Composite Message Types¶
The TypeHelper.compositeHelper
static method handles creating
and parsing composite message types:
// Register the json-xml-json-binary composite message type
amps.TypeHelper.helper(
// The name of the new composite message type
'compositejxjb',
// create the composite type helper
amps.TypeHelper.compositeHelper(
'json', // Part 1: JSON
'xml', // Part 2: XML
'json', // Part 3: JSON
'binary' // Part 4: Binary
)
);
Example 11.1: Register a composite type helper
The composite type helper created with TypeHelper.compositeHelper
will automatically build data to send from the array of the message
parts and parse multi-part messages from the received raw data.
All types used in the new composite type helper should be registered
before creating it.
Building Composite Messages¶
Once the composite type helper was registered, it becomes very easy
to build composite messages of that type. In the following example,
we register a new composite message type, compositejjjb
that
consists of three JSON parts and one binary part. Then, we create
the composite message and publish it. The type helper will take care
of converting message parts into the raw message data that will be
sent:
// Before creating a client, register the composite message type
amps.TypeHelper.helper(
'compositejjjb',
amps.TypeHelper.compositeHelper(
'json', 'json', 'json', 'binary'
)
);
var client = new amps.Client('composite-sender');
client
.connect('ws://localhost:9000/amps/compositejjjb')
.then(function() {
// create the array with message parts
var parts = [
{id: 5, value: 'part1'}, // JSON part 1
{value: 'part2', data: 22.22}, // JSON part 2
{value: 'part3', data: 33.33}, // JSON part 3
'XXXXXXXXXXXXXXXXXXXXXXXXXXX' // Binary data
];
// Publish the composite message
client.publish('composite-topic', parts);
});
Example 11.2: Publish a composite message
Parsing Composite Messages¶
Once the composite type helper is registered, the composite messages
of that type will be parsed automatically. The Message.data
field
will contain the array of message parts, parsed according to their
types:
client.subscribe(function(message) {
var parts = message.data;
console.log('Received message with', parts.length, 'parts');
for (var i = 0; i < parts.length; ++i) {
console.log('Part ' + i + ': ', parts[i]);
}
}, 'composite-topic');
Example 11.3: Consume a composite message
Notice that the receiving application is written with explicit knowledge of the structure and content of the composite message type.
Custom Type Helpers¶
If a message type used in your application is not supported, it is possible to create new type helpers. Another situation in which you might need a custom type helper is when the default implementation does not fit your needs. For example, the default implementation of FIX / NVFIX message types assumes that the keys in each message are unique, thus overriding values if the same key occurs twice in the same message. If your messages contain duplicated keys and that is expected behavior, you need to override the default type helper with a custom implementation.
Each type helper is an object that must contain the following methods:
serialize(data: any): string[]
- this method is used to serialize data in order send it to the server. All data chunks should be converted into an array of strings.deserialize(data: any): any
- this method deserializes data from the Server into a format that will be consumed by the message handler. It can be any format as long as the consumer of the data is aware of it.
Below we provide some examples on how to utilize TypeHelper
functionality.
Create New Type Helpers¶
Create and register a custom type helper for XML
messages:
var xmlTypeHelper = {
serialize: function(data) {
return [new XMLSerializer().serializeToString(data)];
},
deserialize: function(data) {
if (data.constructor === String) {
return new DOMParser().parseFromString(data);
}
else {
// Binary buffer, need to decode utf8
return new DOMParser().parseFromString(
decodeURIComponent(escape(Uint8ToString(data)))
);
}
}
};
// Register the above XML custom helper for parsing XML messages
amps.TypeHelper.helper('xml', xmlTypeHelper);
Example 11.4: Custom Type Helper for XML Messages
Override Default Type Helpers¶
In case the custom parsing behavior is expected, it is possible to override the default type helper:
/**
* create a JSON type helper that does not parse JSON data into native
* JS objects keeping it in form of a string
*/
var jsonHelper = {
serialize: function(data) {
return [data];
},
deserialize: function(data) {
return JSON.stringify(data);
}
};
// override the default type helper
amps.TypeHelper.helper('json', jsonHelper);
Example 11.5: Overriding the default type helper
Register the custom type helper for NVFIX
:
var nvfixTypeHelper = {
serialize: function(data) {
// already formatted fix/nvfix string
if (typeof data === 'string') {
return [data];
}
// otherwise, we assume it's an object with keys and values
return [
Object.keys(data).map(function(key) {
return key + '=' + data[key];
}).join('\x01') + '\x01'
];
},
deserialize: function(data) {
var parsedData = {};
String.fromCharCode.apply(null, new Int8Array(data))
.split('\x01')
.slice(0, -1)
.map(function(keyValue) {
var keyValueTuple = keyValue.split('=');
var key = keyValueTuple[0];
// no '=' inside of the value
if (keyValueTuple.length === 2) {
parsedData[key] = keyValueTuple[1];
}
else {
parsedData[key] = keyValue.slice(key.length + 1);
}
});
return parsedData;
}
};
// Register the above NVFIX custom helper for parsing NVFIX
amps.TypeHelper.helper('nvfix', nvfixTypeHelper);
FIX / NVFIX delimiters¶
In some cases the delimiter value used in FIX / NVFIX messages differs
from the default (\x01
). In this situation you don’t have to
implement a custom type helper; instead, the custom delimiter can
be set:
amps.TypeHelper.helper('nvfix').delimiter('%01');
Example 11.6: Custom Delimiter for NVFIX