Sending and Receiving messages to the X.commerce Fabric
The post first appeared on x.com. https://www.x.com/developers/community/blogs/saranyan/sending-and-receiving-messages-fabric
Publishing/Sending
The X.commerce fabric expects capabilities to communicate via Avro binary messages. Avro is a data serialization system that relies on schemas. When Avro data is read, the schema used for writing should be available. It can be sometimes part of the message payload itself. However, in the case of X.commerce, the schema is not part of the message payload, but is made available through a reference URI. This is a conscious design decision that provides some significant advantages, few of which are listed below -
- Better support for handling JSON and other formats that do not have an embedded schema.
- Smaller message payloads and an ability to cache the schemas, thereby improving the performance.
As mentioned, an additional header is employed to provide a reference to the schema. There are two headers that we need to be aware of in this context. If a publishing capability is using contracts that are approved by the X.commerce team (https://github.com/xcommerce/X.commerce-Contracts), then they are publishing to known topics. In production environments, it is mandatory to publish only to approved topics. For instance, a capability might be using a marketplace contract and publishing to a topic like /marketplace/profile/delete. When such a known topic is used, the publishing capability needs to set a header called X-XC-SCHEMA-VERSION to the contract's version (eg., 1.0.0). This version number will be a value that corresponds to the schema definition found in the Open Commerce Language or X.commerce ontology.
The Fabric, in turn, will convert this and the topic information to a URI in the form of https://<host>/<namespace>/<topic>/<version> that uniquely identifies the that was used to create the message. The receiver of the message just has to look at the header called X-XC-SCHEMA-URI header to fetch the schema.
In sandbox environment, the capabilities are allowed to experiment with custom topics and schemas. To send a message serialized through a custom schema, the capabilities can directly set the schema uri header. For instance, a capability can set the X-XC-SCHEMA-URI to a publicly hosted message contract and the Fabric will not overwrite it, but pass it on to the receiving capability. We need to remember that this is only allowed in development/sandbox mode.
Let us visit a simple example of a publishing capability that publishes a message to the Fabric. Let us use the marketplace contract and send a message to a known topic: /marketplace/profile/delete. I will be showing both Ruby and PHP samples along the way. Let us assume that the capability has been registered with the sandbox and we have a bearer token for authorizing our messages. You can find all about registering capabilities here.
We post messages to the fabric url followed by topic name. The headers that are important to understand are
- Content-Type: Set the content type to avro/binary, which is the type of message that the Fabric expects to communicate in.
- Authorization: When a capability is registered and a tenant authorization is completed, a bearer token is generated. Use that bearer token. You are always communicating on behalf of a tenant. That tenant can sometimes be you, in that case, the SELF bearer token should be used. This is to prove that the publisher has a valid relationship with the tenant. This document talks in greater detail about capabilities and bearer tokens.
- X-XC-SCHEMA-VERSION: This is a numeric value that corresponds to the version of the contract being used
Before the message is posted, it needs to be encoded in Avro/binary using the schema
Error Message
When a capability is registered, it is automatically subscribed to the topic /message/failed. The capability cannot unsubscribe from this topic. The Fabric sends all message delivery errors back to a capability on this topic. Capabilities may not use this topic to deliver application-specific errors. However, if a capability wishes to send an error message to another capability, for instance, a bad field or invalid data, it needs to use X.commerce defined topics to communicate an error. In this example, if we send a message to delete a non-existent profile, the capability can publish back on a topic called /marketplace/profile/delete/failed which can used to indicate a business logic error.
Subscribing/Receiving
We saw a publishing capability send a message to the /marketplace/profile/delete topic, which was delivered to a marketplace capability, which was managing its profile. Logically, this capability needs to know someway if its request was successfully processed. It subscribes to a topic defined in the contract called /markeplace/profile/deleted and /marketplace/profile/delete/failed. When the marketplace capability, receives a message to delete the profile, assuming that the action was successful, it sends a message on /marketplace/profile/deleted. Now, the publisher capability from the previous example sees the following headers -
Using the schema URI, this message can be decoded from Avro binary. Sample code from PHP and Ruby is included -