Integrating with IBM MQ
IBM MQ queues - channels that invoke services, MQMD and MQRFH2 headers, automatic replies and outgoing connections.
Receiving messages from queues
No programming is needed to receive messages from IBM MQ queues. Create an IBM MQ channel in Dashboard, point it to a queue, and a service of your choice will be invoked for each message received.
The message payload will be available in self.request.raw_request.
from zato.server.service import Service
class MyService(Service):
def handle(self):
# The message body
data = self.request.raw_request
# Log what was received
self.logger.info('IBM MQ message: %s', data)
MQMD and MQRFH2 headers
Every message's MQMD descriptor fields are available in self.request.headers, prefixed with "mqmd.".
If a message includes an MQRFH2 header, the way messages sent by JMS applications do, its folders are flattened into the same dictionary - a JMS property like Dst becomes "jms.Dst" and application properties from the usr folder become "usr.my_property".
from zato.server.service import Service
class MyService(Service):
def handle(self):
# MQMD fields
message_id = self.request.headers['mqmd.message_id']
format = self.request.headers['mqmd.format']
# MQRFH2 folders, flattened
destination = self.request.headers['jms.Dst']
tenant = self.request.headers['usr.tenant']
self.logger.info('Message %s for %s', message_id, tenant)
The channel option "Remove JMS headers" controls the payload. When it is on, the MQRFH2 bytes are stripped and self.request.raw_request is the bare message body. When it is off, the payload is left untouched. The headers are exposed in self.request.headers either way.
Replying to messages
When an incoming message names a reply-to queue, assigning to self.response.payload is all that is needed - the response is sent automatically to the reply-to queue at the reply-to queue manager, with its correlation ID set to the request's message ID.
from zato.server.service import Service
class GetBalance(Service):
def handle(self):
account_id = self.request.json['account_id']
# The assignment alone sends the reply
self.response.payload = {'account_id': account_id, 'balance': 512.25}
Sending messages to queues
Create an IBM MQ outgoing connection in Dashboard and use self.ibm_mq to send messages.
The connection is looked up by name, and .send() accepts strings, bytes, dicts, lists or any other JSON-serializable object.
from zato.server.service import Service
class MyService(Service):
def handle(self):
# Get a connection by name
conn = self.ibm_mq['my-publisher']
# Send a string
conn.send('Hello from Zato')
Sending structured data
When you pass a dict or list, it is automatically serialized to JSON before sending.
from zato.server.service import Service
class MyService(Service):
def handle(self):
conn = self.ibm_mq['my-publisher']
conn.send({
'event': 'order.created',
'order_id': '12345',
'customer': 'Acme Corp',
})
Connecting over TLS
Both channels and outgoing connections support TLS. In the connection's Security tab, turn TLS on, pick a cipher spec such as ANY_TLS12_OR_HIGHER and point the CA file to the PEM certificate of the authority that signed the queue manager's certificate. For mutual TLS, add the client certificate and private key PEM files too - no key databases or keystores need to be prepared, PEM files are all that is required.
Testing with a local queue manager
To test your connections without an existing IBM MQ installation, one command starts a complete queue manager in Docker, with default objects ready to use:
docker run -d --rm --name zato-mq -e LICENSE=accept -e MQ_QMGR_NAME=QM1 -e MQ_APP_PASSWORD=zato -p 1414:1414 icr.io/ibm-messaging/mq:latest
The queue manager takes about half a minute to start accepting connections after the container is up. Run the command below to check its status - it exits with an error while the queue manager is still starting and it exits cleanly, with no output, once connections can be made:
The container's developer defaults map to connection details as below:
| Field | Value |
|---|---|
| Address | localhost:1414 |
| Queue manager | QM1 |
| MQ channel | DEV.APP.SVRCONN |
| Queue | DEV.QUEUE.1 (DEV.QUEUE.2 and 3 also exist) |
| Username | app |
| Password | The MQ_APP_PASSWORD value, here zato |
In Dashboard, create an IBM MQ outgoing connection with the details above, set the password through the connection's Change password menu option and click Ping to confirm that Zato can reach the queue manager.
For a complete round trip, add an IBM MQ channel pointing to the same DEV.QUEUE.1 queue and route it to a service of your choice. Each message sent through the outgoing connection will now be consumed by the channel and your service will be invoked with it - a full send and receive loop with no external systems needed.
When you are done, the container removes itself on stop: