Shapes SDK
A powerful little library for interacting with Omneo profile data and keeping UI elements in sync 🤖
Keep it simple
Easy to initialise and access through our set of handy methods
Framework agnostic
Any function can be registered to Shapes SDK to receive updates
Gotta go fast
Caches data using localstorage for instant rendering on reload
Getting started
Shapes SDK exists to provide clear methods for requesting and storing profile data, managing the state of this data and emitting events to subscribed components, on update. It also handles all caching of data and merging of resource requests, to avoid unnecessary requests.
Using the ShapesSDK, developers can easily import Omneo data directly into an application, without the need to interface directly with the Omneo API.
Installing
Using the CDN
<script type=“text/javascript” src=“https://cdn.omneo.io/shapes-sdk/shapes.sdk.js”></script>
When including ShapesSDK from the CDN, the library will be attached to the window and accessible at window.ShapesSDK. When including from npm/yarn ShapesSDK can be used via ES6 import or ES5 require:
//Import examples.
//Imported via the CDN accessible via the window
const ShapesSDK = window.ShapesSDK
//Can be imported as a regular package
import ShapesSDK from '@omneo/shapes-sdk' // Imported via Package
var ShapesSDK = require('@omneo/shapes-sdk') // Imported via Package
Using npm:
$ npm install @omneo/shapes-sdk
Using yarn:
$ yarn add @omneo/shapes-sdk
How to get a token
Secure your tokens
Some implementations may use a proxy url, please check with your Omneo implementation partner to confirm this.
Omneo ID token must first be generated by a secure server process. If you are using an Omneo eCommerce plugin, the token will be generated on login and added to a metafield
First review the Authentication developer documentation, to become familiar with available authentication methods.
Default method
A token can be obtained from your Omneo CX Manager, or generated using API Tokens
Using the Omneo Shopify plugin
Token is stored in local storage with key shapes:omneo:shapestoken:{customer_id}
Firstly, you can check if token exists
var key = 'shapes:omneo:shapestoken:{{customer.id}}'
var token = localStorage.getItem(key);
If token doesn't exist, or token is expired, you need to fetch token and store it with key shapes:omneo:shapestoken:{customer_id} in local storage
- pluginUrl: https://australia-southeast1-omneo-extensions.cloudfunctions.net/shopify/{tenant}/api/v1/auth/token
- customerId: Shopify customer id, {{customer.id}} in liquid
- customerSignature: hashed customer ID, available through liquid template as {{ customer.id | hmac_sha256: shop.metafields.omneo.id_secret }}
{% assign customerId = customer.id %}
{% assign customerSignature = customer.id | hmac_sha256: shop.metafields.omneo.id_secret %}
fetch(`${pluginUrl}/api/v1/auth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id:{customerId},
signature: {customerSignature}
})
})
Once you get token and store it in local storage, you can then initialize shapesClient
- omneo_id_token: get token from local storage
var shapesClient = ShapesSDK.init({
url: ‘https://api.{environment}.getomneo.com/id',
token: ‘{omneo_id_token}’,
logging: true
})
Client Object
Once initialised the shapesClient
object exposes a number of methods for retrieving cached profile data, handling requests to Omneo and subscribing to state updates. All methods interact with the client data state, which follows this structure:
{
“client_id”: uuid,
“loading”: boolean,
“profile”: {
“init”: true,
“error”: false,
“loading”: false,
“data”: {
“id”: “8e697f6b-533d-4837-8680-e7c6b3cde9f0”,
“first_name”: “John”,
“last_name”: “Smith”,
…
}
}
}
Methods
- find
- hydrate
- on
- off
.init()
Returns a client
object
When initialising the ShapesSDK, the init function requires an Omneo ID (or proxy) url
and an Omneo ID token
. The constructor also allows an optional flag to be set, to enable console logging, for debugging logging
var shapesClient = ShapesSDK.init({
url: 'https://api.{environment}.getomneo.com/id',
token: '{omneo_id_token}',
logging: true
})
Omneo ID token must first be generated by a secure server process. If you are using an Omneo eCommerce plugin, the token will be generated on login and added to a
metafield
Some implementations may use a proxy url, please check with your Omneo implementation partner to confirm this.
.find()
Traverses and returns value from the shapes data state, using a path in dot . format.
Arguments
path - Dot notation path to data in state
Returns
Value from existing shapesClient state. If no value is found, null is returned.
Note
This method is not responsible with fetching new data. When shapesClient loads, it will pull all cached data and a fresh set of top level profile data. If an endpoint such as transactions is required, register this with the hydrate() method below, which will then fetch from the Omneo API.
Example
let transactions = shapesClient.find(‘transactions’); // Get all
transactions
let combined_balance = shapesClient.find(‘balances.combined_balance_dollars’) // Get first transaction by index
let loading = shapesClient.find(‘loading’); // Get loading state
let state = shapesClient.find(); // Get shapes state
.hydrate()
Registers that shapesClient must retrieve the given endpoint. If the data has not already been fetched, shapesClient will get this data from Omneo and merge it into the client state. Once initialized, shapesClient will then emit the relevant shapes.{endpoint}.ready event.
Arguments
- path - Dot notation path to endpoint
Returns
true if there were no exceptions. All updates should be watched for through the .on() method
Example
shapesClient.hydrate(‘transactions’)
shapesClient.hydrate(‘profile’)
shapesClient.hydrate(‘lists’)
.on()
Allows you to add handlers to a shapesClient event. You can register multiple handlers to the same event, by calling this function for each. Each time the event with event_name is triggered, all handlers for this name will be called with event data passed as an argument.
For available events, see Events
Arguments
- event_name - Dot notation event name
- handler - Function with single data argument, to be executed on event
Returns
The value of that event’s relevant endpoint. Note that list endpoints are transformed into keyed objects for ease of state management.
Example
let handler = function(data){
console.log(data);
};
let profile = shapesClient.on(‘profile.update’, handler);
// console.log
// {
// “init”: true,
// “error”: false,
// “loading”: false,
// “data”: {
// “id”: “8e697f6b-533d-4837-8680-e7c6b3cde9f0”,
// “first_name”: “John”,
// “last_name”: “Smith”,
// …
// }
// }
.off()
Allows you to remove a handler for a shapesClient event.
For available events, see Events
Arguments
- event_name - Dot notation event name
- handler - Function with single data argument, to be executed on event
Returns
true if event listener was unregistered correctly
Example
let handler = function(data){
// Do something with data
};
shapesClient.off(‘profile.update’, handler);
.dispatch()
Dispatches an action directly to the internal store to manually manage state. The internal store reducer handles a number of action types.
[resource].update
Will merge the payload into the top level resources. Special consideration is given to data so it will be merged and not overwrite the existing state. Ensure that for resources such as transactions the array of items has been converted to an object with id as key.
{
“type”: “profile.update”,
“payload”: {
“error”: false,
“data”: {
“first_name”: “John”
}
}
}
[resource].add
An alias of update that is used when adding new items to resource lists, such as rewards or transactions
[resource].remove
Removes a key from the {resource}.data object by specifying the key in the payload
{
“type”: “transaction.remove”,
“payload”: {
“id”: “5”
}
}
[resource].set
Merges the payload against the whole state object. Special provisions are not made for data and anything included in the set payload will overwrite the existing state. This is especially useful if you are managing the whole state manually.
{
“type”: “lists.set”,
“payload”: {
“init”: true,
“loading”: false,
“data”: {
“5”: {…},
“27”: {…}
}
}
}
[resource].load
Sets the loading state of a resource. This does not merge any other payload keys. This is useful for setting loading: true before a http request etc.
{
“type”: “profile.load”,
“payload”: {
“loading”: true
}
}
[resource].reset
Resets the resource back to the initial state of the reducer. Useful for clearing if cached data is malformed or if there has been an error.
{
“type”: “lists.reset”,
}
Arguments
Dispatch receives a single action object, with type and payload keys to update the state.
- type - Action type, using . separator to designate the resource. eg. profile.set
- payload - Object containing key/values to update in state. Refer to the action types for examples and accepted keys for each type
Returns
undefined
Example
shapesClient.dispatch({
type: ‘profile.update’,
payload: {
data: {
first_name: “John”,
last_name: “Smith”,
email: “[email protected]”
}
}
})
shapesClient.dispatch({
type: ‘transacitons.add’,
payload: {
data: {
“5”:{
id: 5,
items: […]
}
}
}
})
shapesClient.dispatch({
type: ‘lists.remove’,
payload: {
data: {
id: 5
}
}
})
Requests
Shapes provides methods for making authenticated requests to all profile endpoints in Omneo. In addition, the shapes requests methods allow for automatic updating of top level profile objects such as transactions
Note
Currently the Request methods do not support automatic state updates of deeply nested objects, such as items within a list eg. lists.1.items.4
Methods
// GET
shapesClient.get(path, params, updateState)
// POST
shapesClient.put(path, data, updateState)
// PUT
shapesClient.post(path, data, updateState)
// DELETE
shapesClient.delete(path, false, updateState)
Arguments
- path - Dot notation path to endpoint
- data - Body payload for PUT and POST requests
- params - GET parameters, used to filter and paginate browse/list requests
- updateState - A boolean flag automatically merge request response into the state and emit update events to all subscribers.
Returns
A JavaScript Promise object. Once resolved, this method will return the value of that endpoint.
Example
shapesClient.get(‘profile’).then(response=>{
// Do something with profile data
})
shapesClient.post(‘profile’, { first_name: “James” }, true).then(response=>{
// Profile object with updated “new_name” field
})
shapesClient.put(‘lists.6’, { id: 2, title: ‘New List Item’ }, true).then(() => {
// Added new item to a list with the id of 6
})
shapesClient.delete(‘list.6’, true).then(response => {
// Delete entire list with id of 6
// response.status = 204 no content
})
Events
As the shapesClient manages all state and requests internally, it exposes a number of events to keep subscribed components up to date. These events are emitted through 2 differend streams. The first is to subscribers of shapesClient.on(‘{event_name}’) and the second is to the native browser js Event() handler.
Note: In addition to the methods below, the shapesClient also emits all events to the document as custom named events.
Event structure
Events are defined by an event type and payload. Shapes will emit general events for when the client is initialized and for any state update. It will also emit events for profile.ready and profile.update as well as ready and update events for all individual endpoints. Events will include the UUID for the shapesClient as well as a loading indicator to confirm if an update event represents a loading state for that state object.
Event types
- shapes.ready
- shapes.update
- shapes.{endpoint}.ready
- shapes.{endpoint}.load
- shapes.{endpoint}.update
shapes.{event_type}
shapes.{resource}.{event_type}
{
“init”: true,
“error”: false,
“loading”: false,
“data”: {
“id”: “8e697f6b-533d-4837-8680-e7c6b3cde9f0”,
“first_name”: “John”,
“last_name”: “Smith”,
…
}
}
Updated over 2 years ago