Ask Your Question

Revision history [back]

Is it good practice to use the ros2 json message, ie, in a standard message like std_msgs / string, write a string with a json structure?

I would say "no".

One of the main points of using standardised messages is because they allow you to encode both syntax (ie: the exact form of data (layout, sizes of fields, etc)) and the semantics (ie: the meaning (so x is the first element of a vector that has its origin at frame_id)) in a single definition.

This allows both consumers and producers of such messages to be very explicit about the information they are communicating, and allows things like decoupling in time (ie: a consumer that receives messages that were produced 2 years ago should still be able to interpret them).

Your suggestion essentially comes down to using a field of type string and populating it with data that syntactically fits that field perfectly fine (a JSON string is still a string), but semantically seems like a bad fit: a JSON string is not just a string, it's (typically) actually a stringified (ie: serialised) representation of some higher order data structure (such as a list, map or even worse: arbitrary application-specific classes).

Interpretation of that string field now has two "layers" (in contrast to the 'normal' situation where we use only appropriate msg types):

  1. the middleware layer where the sequence of bytes coming in as part of a message is supposed to be a string
  2. the application layer where "special knowledge" is required to know that this string is not just a string, but actually requires interpretation again to be able to get the actual message content out of it

We could say that "special knowledge" (ie: layer 2) is always required to be able to interpret a message, but the main difference here is that by using properly typed messages the special knowledge is (at least partly) embedded in the contract that exists between the producer and consumer: it's the semantics part of the message definition. That is very powerful, as it greatly reduces coupling between the producer and consumer: very little knowledge of the internals of the producer are imported into the consumer, making things like replacing components and mixing-and-matching components to create applications a lot easier, as neither will assume (too much) about the other.

If producer A starts putting JSON (or anything that is not actually really a plain string) into a field, the correct interpretation of that field completely depends on consumer B knowing that field contains JSON (and not just an arbitrary plain string). This couples A and B, as they both must assume their communication channel works that way, or they can't function.


Note that a similar argument can be made for all message types in the std_msgs package: a std_msgs/String doesn't convey much semantics, neither does publishing a temperature measurement as a std_msgs/Float64. That is also the reason that direct usage of messages in std_msgs is discouraged: it's always better to use a more semantically meaningful type for your topics, as that will allow consumers to reuse the contract (ie: knowledge) that comes with those message types.

Is it good practice to use the ros2 json message, ie, in a standard message like std_msgs / string, write a string with a json structure?

I would say "no".

One of the main points of using standardised messages is because as we do in ROS is that they allow you to encode both syntax (ie: the exact form of data (layout, sizes of fields, etc)) and the semantics (ie: the meaning (so x is the first element of a vector that has its origin at frame_id)) in a single definition.

This allows both consumers and producers of such messages to be very explicit about the information they are communicating, and allows things like decoupling in time (ie: a consumer that receives messages that were produced 2 years ago should still be able to interpret them).

Your suggestion essentially comes down to using a field of type string and populating it with data that syntactically fits that field perfectly fine (a JSON string is still a string), but semantically seems like a bad fit: a JSON string is not just a string, it's (typically) actually a stringified (ie: serialised) representation of some higher order data structure (such as a list, map or even worse: arbitrary application-specific classes).

Interpretation of that string field now has two "layers" (in contrast to the 'normal' situation where we use only appropriate msg types):

  1. the middleware layer where the sequence of bytes coming in as part of a message is supposed to be a string
  2. the application layer where "special knowledge" is required to know that this string is not just a string, but actually requires interpretation again to be able to get the actual message content out of it

We could say that "special knowledge" (ie: layer 2) is always required to be able to interpret a message, but the main difference here is that by using properly typed messages the special knowledge is (at least partly) embedded in the contract that exists between the producer and consumer: it's the semantics part of the message definition. That is very powerful, as it greatly reduces coupling between the producer and consumer: very little knowledge of the internals of the producer are imported into the consumer, making things like replacing components and mixing-and-matching components to create applications a lot easier, as neither will assume (too much) about the other.

If producer A starts putting JSON (or anything that is not actually really a plain string) into a field, the correct interpretation of that field completely depends on consumer B knowing that field contains JSON (and not just an arbitrary plain string). This couples A and B, as they both must assume their communication channel works that way, or they can't function.


Note that a similar argument can be made for all message types in the std_msgs package: a std_msgs/String doesn't convey much semantics, neither does publishing a temperature measurement as a std_msgs/Float64. That is also the reason that direct usage of messages in std_msgs is discouraged: it's always better to use a more semantically meaningful type for your topics, as that will allow consumers to reuse the contract (ie: knowledge) that comes with those message types.

Is it good practice to use the ros2 json message, ie, in a standard message like std_msgs / string, write a string with a json structure?

I would say "no".

One of the main points of using standardised messages as we do in ROS is that they allow you to encode both syntax (ie: the exact form of data (layout, sizes of fields, etc)) and the semantics (ie: the meaning (so x is the first element of a vector that has its origin at frame_id)) in a single definition.

This allows both consumers and producers of such messages to be very explicit about the information they are communicating, and allows things like decoupling in time (ie: a consumer that receives messages that were produced 2 years ago should still be able to interpret them).

Your suggestion essentially comes down to using a field of type string and populating it with data that syntactically fits that field perfectly fine (a JSON string is still a string), but semantically seems like a bad fit: a JSON string is not just a string, it's (typically) actually a stringified (ie: serialised) representation of some higher order data structure (such as a list, map or even worse: arbitrary application-specific classes).

Interpretation of that string field now has two "layers" (in contrast to the 'normal' situation where we use only appropriate msg types):

  1. the middleware layer where the sequence of bytes coming in as part of a message is supposed to be a string
  2. the application layer where "special knowledge" is required to know that this string is not just a string, but actually requires interpretation again to be able to get the actual message content out of it

We could say that "special knowledge" (ie: layer 2) is always required to be able to interpret a message, but the main difference here is that by using properly typed messages the special knowledge is (at least partly) embedded in the contract that exists between the producer and consumer: it's the semantics part of the message definition. That is very powerful, as it greatly reduces coupling between the producer and consumer: very little knowledge of the internals of the producer are imported into the consumer, making things like replacing components and mixing-and-matching components to create applications a lot easier, as neither will assume (too much) about the other.

If producer A starts putting JSON (or anything that is not actually really a plain string) into a field, the correct interpretation of that field completely depends on consumer B knowing that field contains JSON (and not just an arbitrary plain string). This couples A and B, as they both must assume their communication channel works that way, or they can't function.

To make it more explicit: even though the message definition tells me that consumer B accepts a string, if I send it anything but JSON, B will fail to process the message, even though both syntax and semantics have been adhered to (but note that string is a less-than-ideal type for this sort of communication as well, see below).


Note that a similar argument can be made for all message types in the std_msgs package: a std_msgs/String doesn't convey much semantics, neither does publishing a temperature measurement as a std_msgs/Float64. That is also the reason that direct usage of messages in std_msgs is discouraged: it's always better to use a more semantically meaningful type for your topics, as that will allow consumers to reuse the contract (ie: knowledge) that comes with those message types.