RabbitMQ - Send a JSON message - rabbitmq

I send the following message with content type application/json:
However whene i get messages from the same RabbitMQ Web console, it shows the payload as String.
What am I doing wrong? Or am I fundamentally misunderstanding and the Payload is always of type String?

From the official docs:
AMQP messages also have a payload (the data that they carry), which AMQP brokers treat as an opaque byte array. The broker will not inspect or modify the payload. It is possible for messages to contain only attributes and no payload. It is common to use serialisation formats like JSON, Thrift, Protocol Buffers and MessagePack to serialize structured data in order to publish it as the message payload. AMQP peers typically use the "content-type" and "content-encoding" fields to communicate this information, but this is by convention only.
So basically, RabbitMQ has no knowledge on JSON, messages all are just byte arrays to it

From NodeJS Context:
If we want to send JSON object as message, we may get the following error:
The first argument must be of type string or an instance of Buffer,
ArrayBuffer, or Array or an Array-like Object. Received an instance of
Object
So, we can convert the JSON payload as string and parse it in the worker. We stringify the JSON object before sending the data the Queue-
let payloadAsString = JSON.stringify(payload);
And from worker's end, we can then JSON.parse
let payload = JSON.parse(msg.content.toString());
//then access the object as we normally do, i.e. :
let id = payload.id;

For anyone using .Net to send objects via RabbitMQ.
You have to serialise your JSON object to byte array, send via RabbitMQ then de-serialise after receiving. You can do this like this:
Install the Newtonsoft JSON library
using Newtonsoft.Json;
Create a model for your JSON object message (in this case AccountMessage)
Serialise your object into byte array like this:
byte[] messagebuffer = Encoding.Default.GetBytes(JsonConvert.SerializeObject(accountMessage) );
After receiving the message data, you can de-serialise like this:
AccountMessage receivedMessage = JsonConvert.DeserializeObject<AccountMessage>(Encoding.UTF8.GetString(body));

from here
Content Type and Encoding
The content (MIME media) type and content encoding fields allow publishers communicate how message payload should be deserialized and decoded by consumers.
RabbitMQ does not validate or use these fields, it exists for applications and plugins to use and interpret.
by the way, using the rabbitMQ web gui, you use the words content_type, however in code (javascript confirmed), you use the key name contentType. it's a subtle difference, but enough to drive you crazy.

Related

Convert InputStream to Flux<MyClass>

We are given an InputStream which represents the response body of a text/event-stream HTTP response. The stream emits events periodically, every few seconds.
Now we need to find a way to convert this InputStream into Flux<MyClass>. The goal is to use a StepVerifier on that stream, to check that each object has the expected structure, and to close the stream in the end.
How could this be done?

How to use protobuf reflection to guarantee deterministic serialisation

Proto3 release notes states:
The
deterministic serialization is, however, NOT canonical across languages; it
is also unstable across different builds with schema changes due to unknown
fields. Users who need canonical serialization, e.g. persistent storage in
a canonical form, fingerprinting, etc, should define their own
canonicalization specification and implement the serializer using reflection
APIs rather than relying on this API.
What I would like to achieve is to have a deterministic serialisation of protobuf message to carry a crypto signature along with it. As I understand due to differences in serialisers binary data could differ and signature would become invalid.
package Something
message Request {
Payload payload = 1;
// signature of serialised payload
bytes signature = 2;
message Payload {
string user_id_from = 1;
uint64 amount = 2;
string user_id_to = 3;
}
}
What is the way to do this using protobuf reflection?
This doesn't answer the question directly, but may solve your issue: don't store the payload as a message, but store the serialized bytes alongside with the signature.
message Request {
// Serialized Payload message.
bytes payload = 1;
// signature of serialised payload
bytes signature = 2;
}
message Payload {
string user_id_from = 1;
uint64 amount = 2;
string user_id_to = 3;
}
This may be a little less convenient to work with in code, but has the advantage of preserving all the forwards and backwards-compatibility guarantees of protobuf.
It also frees you from serializing the message twice when writing it (once as a subfield, once to get the signature).

CEP rule to update fragments within a managed object

I need to be able to create an event processing rule that when you add a new device, you take a string value from one fragment (e.g.: c8y_Hardware.imei) and use that string to populate another fragment (e.g: c8y_Mobile.imei). So the new device would then have the same value in both c8y_Hardware.imei and c8y_Mobile.imei.
We have attempted setting up the appropriate CEP rules, but they are not working (they do compile and save).
insert into UpdateManagedObject
select
m.id as id,
{
"c8y_Mobile.imei", getString(m,"c8y_Hardware.imei")
} as fragments
from
ManagedObjectCreated as m
where
getString(m,"c8y_Hardware.imei") != "";
Any guidance on where we are messing up our syntax would be greatly appreciated.
It should be: m.managedObject.id as id.
Usually you would also get an error on compile but it can be that the streams also have an id so that it technically works in CEP. You should be able to check if it triggers on the debug stream and see the id that has been set.
Same applies for all other Cumulocity streams. The streams itself e.g. ManagedObjectCreated or AlarmUpdated etc. are not the objects directly. They have always a property like in this case managedObject or for AlarmUpdated it is alarm. This property is the actual payload.
The helper methods like getString are written in a way that you can pass either the payload or the full stream object so there it does not matter.

Modifying ServiceStack's JSON output

I have to build a REST service with ServiceStack; the responses must have a certain format. Both JSON and XML are to be supported. The standard serializers do not return the response in the format I need.
For JSON, it would be enough to wrap the result, e.g. if a function returns a list of Site objects, the JSON serializer gives me [{...}, ...], but I need {"Sites": [{...}, ...]}. The requested content-type would be "Sites+json" in this case. For other functions, "Sites" would be replaced by something else.
How can I achieve this?
Edit:
The XML has to be the direct "translation" of the JSON, like
<Sites>...</Sites> instead of {"Sites":...}.
The standard XML serialization works differently, it always puts in the data type as well.
Has anyone an idea how to do this? I guess I have to write my own XML serializer and map all my XML types (like Sites+xml,...) to it?

Passing a default Integer value to a WCF service in Biztalk

I have consumed WCF service in biztalk through "Add generated items". There is a method in WCF which takes an integer parameter. In orchestration I want to pass that method a default value or say I want to hard code input value. How I can achieve this. I have googled this question but didn't get any adequate result.
What I have done is declared an integer variable assign it a value, then I assigned that variable to a message of Integer type.
Now how I can assign this message to WebService Request type message?
or how I can transform integer type message to WebService Request type message?
There are a bunch of ways to do this:
If you are mapping the request from another message, you can hard code it in the map - click on the field in the RHS of the Map Editor and set the hard coded value in the Value in the Property box
After creating a (dummy) request message, you can set the value using xpath() in an expression message assignment shape
xpath(myRequestMessage, "//*[local-name()='NameOfFieldHere']") = 3; // Or set to it your variable
If the field is distinguished in your schema, you can use the distinguished field instead of xpath, viz in an expression message assignment shape:
myRequestMessage.NameOfFieldHere = 3;
(And note if its a multipart message, then it will be myRequestMessage.Part.NameOfFieldHere OFC)
One disclaimer: I've assumed the WCF service request message is trivial, i.e. just a single integer field. If your message is large, using //local-name() ... isn't recommended, since
There may be more than one node with with the name NameOfFieldHere
The XSL parser used by BizTalk is slow and resource intensive when evaluating large xml documents with //
Biztalk Scheduler Adapter is really helpful in this case. It generates desired XML on predefined scheduled set by the user. So fill up your XML with hard coded values and receive them through this adapter.