Basics
The Business Events configurations database is not multi-tenant, meaning it can contain contain configuration for just one tenant.
Clients
Start by creating the clients:
DECLARE @clientCrm UNIQUEIDENTIFIER
DECLARE @clientDocuments UNIQUEIDENTIFIER
EXEC CreateOrGetClient 'crm-lime', @clientCrm OUTPUT
EXEC CreateOrGetClient 'documents-sharepoint', @clientDocuments OUTPUT
Possible naming conventions
- [capability]-[system], e.g. "crm-lime"
- [capability], e.g. "crm"
- [system], e.g. "lime"
Note!
To be able to translate values int Nexus Value Translator, use the same client names as in the valuetranslations database.
Events, Publications and Subscriptions
The database structure has a few tables for representing an event.
Static configuration
Use stored procedures to handle the configuration for you:
DECLARE @minorId UNIQUEIDENTIFIER
DECLARE @majorId UNIQUEIDENTIFIER
DECLARE @publicationId UNIQUEIDENTIFIER
EXEC CreateOrGetEventWithVersion '<Entity name>', '<Event name>', <Major version>, <Minor version>, '{
<contract>
}', @majorId OUTPUT, @minorId OUTPUT
EXEC CreateOrGetPublication @clientCrm, @minorId, @publicationId OUTPUT
EXEC CreateOrUpdateSubscription @clientDocuments, @publicationId, '$(ClientDocumentsProductUpdatedUrl)'
DECLARE @priority INT = 2
EXEC CreateOrUpdateSubscription @clientX, @publicationId, '$(ClientXProductUpdatedUrl)', @priority
-- Legacy
DECLARE @publicationId UNIQUEIDENTIFIER = '<guid>'
IF NOT EXISTS (SELECT 1 FROM Publication WHERE Id = @publicationId)
INSERT INTO Publication (Id, ClientId, EventMinorVersionId) VALUES (@publicationId, @clientCrm, @minorId)
EXEC CreateOrUpdateSubscription @clientDocuments, @publicationId, '$(ClientDocumentsProductUpdatedUrl)'
DECLARE @priority INT = 2
EXEC CreateOrUpdateSubscription @clientX, @publicationId, '$(ClientXProductUpdatedUrl)', @priority
Attribute | Description | Example |
---|---|---|
CreateOrGetEventWithVersion |
Creates an event that some client can publish and other client subscibe to | |
<Entity name> |
The entity that the event is happening for | Product, Person, Document |
<Event name> |
The name of the event | Created, LoggedIn, Deleted |
<Major version> |
Use same major as long as no breaking changes are made (such as renamed or deleted attributes in the contract) | 1, 2 |
<Minor version> |
Change the minor version when adding an attribute | 0, 1, 2 |
<contract> |
A json object describing the fields of the event | See more below |
@majorId |
The id of the created MajorVersion | |
@minorId |
The id of the created MinorVersion, containing the Json contract | |
@publicationId |
A unique identifier (GUID) for a client's publication | |
CreateOrGetPublication |
Creates a publication for a client, or returns existing | |
CreateOrUpdateSubscription |
Creates a subscription for a client on the specified url | |
$(Client<Client name><Entity><Event>Url) |
A variable name representing the client's webhook url for this event. Could also be the url instead of variable. | $(ClientDocumentsProductUpdatedUrl) |
@priority |
A subscription can have a priority level so that the webhook call ends up on a prioritized queue. The default value is NULL. Note! you need to configure priority queues in Async Caller |
NULL (default), 1, 2, 3, ... |
Dynamic subscription registration (available in BE version 1.13.0)
You can have a client register it's own subscriptions.
- Register the client with DynamicalRegistration
- Expose the subscription registration endpoint from Nexus Business Event throgh the Business API
- Let the client register it's subscriptions at runtime
DECLARE @clientX UNIQUEIDENTIFIER
EXEC CreateOrGetClient2 'dyna-x', 1, @clientX OUTPUT
where 1
means that the client has DynamicalRegistration
.
Note: When calling the subscription registration endpoint, all the subscriptions for the client will be replaced.
Event contract
Each event has a JSON contract with attributes of certain types.
Type | Example | Comment |
---|---|---|
int | 12, -31 | An integer number |
double | 9.00982, -1.0 | A double precision number |
bool | true, false | A boolean value |
string | "Hello world" | A UTF-8 string value |
iso8601date | "2019-05-20" | An ISO date, without time |
iso8601datetime | "2019-05-20T13:29:00+02:00" | An ISO date with time |
"name@example.com" | An email address | |
Value translator concept | "product.id" | Used for value translations between clients |
Array | "OrderLines": [ { "Id": "string", ... } ] | Define the object inside array brackets |
Example
EXEC CreateOrGetEventWithVersion 'Product', 'Purchased', 1, 0, '{
"ProductId": "product.id",
"PurchasedBy": "person.id",
"PurchasedAt": "iso8601datetime"
"ItemCount": "int",
"OrderLines": [
{
"Id": "string",
"ArticleNumber": "string",
"Count": "int"
}
]
}', @majorId OUTPUT, @minorId OUTPUT
Optional attributes
Sometimes optional attributes are needed, e.g. if only one of two attributes have a value. To configure an attribute as optional, use the syntax
"<attribute name>": "<type> | null"
Example
{
"WorkingPlaceId": "string | null",
"UnitId": "string | null"
}
Versioning
All events have a Major and Minor version. They start out at 1.0 and backward compatible changes bumps the Minor version, whereas non-compatible changes bumps the major version.
Meta data on each event
When an event is sent, a MetaData
attribute is automatically added:
{
ProductId: ...,
...
MetaData: {
MessageId: "string",
PublisherName: "string; (client name, see above)",
EntityName: "string",
EventName: "string",
MajorVersion: "integer",
MinorVersion: "integer",
PublishedAt: "iso8601datetime"
}
}
Test bench
Event publishers will want to verify their publications, either manually or as part of an integration test suite.
For this purpose, expose an endpoint in the platform api (calling Nexus Business Events test bench) which will respond with a PublicationTestResult object.
POST https://api.acme.com/BusinessEvents/TestBench/{Entity}/{Event}/{MajorVersion}/{MinorVersion}?client={client}
{
"Attribute1": "value1",
"Attribute2": "value2",
...
}
200 OK
{
Verified: "bool",
Errors: [ "...", "...", ... ]
Contract: { ... }
Payload: { ... }
}
(Note that the response code is always 200, even if Verified == false
.
Variables
Configuration is very similiar across environments, so working with variables in the sql script is a way to reduce the number of files needed in the repository. In these examples we use the Azure Devops syntax for variables, $(VariableName)
.
Automation
One way to use continous integration for the seeding is like in this guide: Continuous integration for database seeding