Appearance
PlatformHub Schemas
PlatformHub is an events based system, and it is designed in such a way as not to create interdependencies between plugins that communicate with each other.
As described before, this is done via messages. These messages can carry JSON payloads containing objects with primitive values. Therefore there are no traditional API contracts to make sure we're calling the right function with the right parameters.
With this in mind, how do we make sure we're sending the correct payload when we send a command or query and, how do we know what to expect when receiving a payload from an eventStream to which we're subscribed? Enter JSON schemas!
With JSON schemas each plugin can define the structure and typing of all the payloads it will receive/send according to what is declared in its Policy.
With that in mind let's look at a sample Policy file and how to construct a schema out of the messages declared in it.
Constructing Schemas
JSON
{
"name": "AccountsPlugin",
"publish": {
"eventStreams": []
},
"subscribeOnDemand": {
"eventStreams": [
{
"pluginName": "AccountsDomainModelPlugin",
"messageName": "accountsListUpdated"
},
]
},
"send": {
"commands": [
{
"pluginName": "AccountsDomainModelPlugin",
"messageName": "fetchAccountsList"
}
]
}
}Parts of the Policy are hidden for clarity purposes
The Accounts plugin sends a command fetchAccountsList to the AccountsDomainModelPlugin and subscribes on demand for the accountsListUpdated eventStream returned by the AccountsDomainModelPlugin
JSON
{
"name": "AccountsDomainModelPlugin",
"publish": {
"eventStreams": [
{
"pluginName": "AccountsDomainModelPlugin",
"messageName": "accountsListUpdated"
},
]
},
"receive": {
"commands": [
{
"pluginName": "AccountsDomainModelPlugin",
"messageName": "fetchAccountsList"
},
],
}
}The AccountsDomainModelPlugin receives a fetchAccountsList command and publishes an accountsListUpdated event.
From this we can see the correlation between the two plugins and how the two policies are compatible. By adding schemas into the mix we can make sure there's also compatibility between the payloads being sent.
Schemas naming conventions
Before we delve deeper into how schemas are built, a quick word about naming conventions.
Payloads are divided into groups based on the Policy structure:
- Send
- Receive
- Publish
- SubscribeOnDemand
- SubscribeOnStartup (doesn't take payloads)
- PublishToTopic
- SubscribeToTopic
For each of them there can be inputPayload(s) and outputPayload(s).
In our example the AccountsDomainModelPlugin will declare one InputPayload for the fetchAccountsList command and one InputPaylad and one OutputPayload for the accountsListUpdated eventStream.
These will be named according to the following convention
For send and subscribe message types:
{MessageContext}.{MessageType}.{PluginName}.{MessageName}.{PayloadType}.schema.jsonFor receive and publish message types:
{MessageContext}.{MessageType}.{MessageName}.{PayloadType}.schema.jsonFor publishToTopic message type:
PublishToTopic.TopicStream.{TopicName}.{TopicMessageName}.OutputPayload.schema.jsonFor subscribeToTopic message type:
SubscribeToTopic.TopicStream.{TopicName}.{TopicMessageName}.InputPayload.schema.jsonNow that we know this, we can name our three payloads for the AccountsDomainModelPlugin
Receive.Command.FetchAccountsList.InputPayload.schema.jsonPublish.EventStream.AccountsListUpdated.InputPayload.schema.jsonPublish.EventStream.AccountsListUpdated.OutputPayload.schema.json
Let's have a look at what those above mean:
- The payload that
AccountsDomainModelPluginaccepts when plugins are sending it thefetchAccountsListcommand - The payload that
AccountsDomainModelPluginaccepts when returning the publisher that will emitaccountsListUpdatedvalues - The payload that
AccountsDomainModelPluginsends when emitting values via the publisher for theaccountsListUpdatedeventStream.
Now since the AccountsPlugin wants to communicate with the AccountsDomainModelPlugin it will have to declare schemas that are compatible with what's been done above.
It will declare:
Send.Command.AccountsDomainModelPlugin.FetchAccountsList.InputPayload.schema.jsonSubscribeOnDemand.EventStream.AccountsDomainModelPlugin.AccountsListUpdated.InputPayload.schema.jsonSubscribeOnDemand.EventStream.AccountsDomainModelPlugin.AccountsListUpdated.Output.schema.json
What these mean:
- The payload the
AccountsPluginsends with thefetchAccountsListcommand toAccountsDomainModelPlugin - The payload the
AccountsPluginsends when asking for a publisher (only for SubscribeOnDemand since SubscribeOnStartup doesn't take any input payloads) that will emit theaccountsListUpdatedvalues - The payload the
AccountsPluginexpects from theAccountsDomainModelPluginpublisher emitting values foraccountsListUpdated
It becomes clear that in order for the two plugins to be compatible, the corresponding schemas need to have matching fields between what AccountsDomainModelPlugin sends and what AccountsPlugin expects and vice versa.
For further details on schemas naming conventions please visit our Confluence page
Constructing Schemas (continued)
Let's now look in more detail at the contents of the different schemas
- The
AccountsDomainModelPlugindoes not expect to receive any payload with thefetchAccountsListcommand therefore it declaresReceive.Command.FetchAccountsList.InputPayload.schema.jsonas a "null" payload
JSON
{
"type": "null"
}As already observed, AccountsPlugin needs to have an identical counterpart, which is going to be Send.Command.AccountsDomainModelPlugin.FetchAccountsList.InputPayload.schema.json and it too will be a "null" payload
JSON
{
"type": "null"
}- The
AccountsDomainModelPlugindoes not require any payload when being asked for the publisher foraccountsListUpdatedonsubscribeOnDemandtherefore again it will declare a "null" payload forPublish.EventStream.AccountsListUpdated.InputPayload.schema.json
JSON
{
"type": "null"
}And the same is true for the AccountsPlugin schema SubscribeOnDemand.EventStream.AccountsDomainModelPlugin.AccountsListUpdated.InputPayload.schema.json
AccountsDomainPlugindeclares that it will send a list of accounts as a payload when emitting values foraccountsListUpdatedand it does that in the schemaPublish.EventStream.AccountsListUpdated.OutputPayload.schema.json
JSON
{
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"accountNumber": {
"type": "string"
},
"kind": {
"enum": [
"current",
"savings",
"credit"
]
},
"isPrimary": {
"type": "boolean"
},
"balance": {
"type": "number",
"minimum": 0
},
},
"required": [
"name",
"accountNumber",
"isPrimary",
"kind"
],
"additionalProperties": false
}
}This schema shows that the payload must be an array, and the array will contain objects with certain properties (these actually describe the properties of an Account), of which some are required: name, accountNumber, isPrimary and kind
We know that the AccountsPlugin must declare what it expects to find inside the payload that it receives from the accountsListUpdated eventStream. This means that AccountsPlugin expects exactly what AccountsDomainModelPlugin sends, therefore they're compatible.
For more information on how JSON schemas work please visit JSON Schemas
Further details about how to create schemas for iOS can be found here.
Validation
A common validation script needs to be added to your IDE and will run at compile time, when building your host app. If all schemas are compatible it will succeed, otherwise it will surface errors in console guiding you through what's wrong with your schemas and the fixes needed. For more information on the tool and how to use it please see plarform-hub-tools
Suffix / File Extension
Must exactly match ".schema.json" in lower case
Example List of Schema Files Used in the iOS Reactive POC Sample App
- Publish.EventStream.AccountBalanceUpdated.InputPayload.schema.json
- Publish.EventStream.AccountBalanceUpdated.OutputPayload.schema.json
- Publish.EventStream.AccountTransactionBatchUpdated.InputPayload.schema.json
- Publish.EventStream.AccountTransactionBatchUpdated.OutputPayload.schema.json
- Publish.EventStream.AccountsListUpdated.InputPayload.schema.json
- Publish.EventStream.AccountsListUpdated.OutputPayload.schema.json
- Receive.Command.FetchAccountBalance.InputPayload.schema.json
- Receive.Command.FetchAccountTransactionBatch.InputPayload.schema.json
- Receive.Command.FetchAccountsList.InputPayload.schema.json
- Receive.Command.UpdateAccountIsPrimary.InputPayload.schema.json
- Send.Command.NetworkPlugin.PerformRequest.InputPayload.schema.json