Skip to content

Architecture

Component overview

The library is organized around four core components:

Session
The main entry point. Owns authentication, base URL construction, request/response handling, and diagnostic state. Provides generated command methods for all MQSC commands. A single session represents a connection to one queue manager's REST API.
Command methods
~144 generated MQSC command methods. Each method is a thin wrapper that calls the internal command dispatcher with the correct command verb and qualifier. Method names follow the pattern verb_qualifier (or verbQualifier in camelCase languages), mapping directly to MQSC commands. For example, DISPLAY QUEUE becomes display_queue / displayQueue, and DEFINE QLOCAL becomes define_qlocal / defineQlocal.
Ensure methods
16 idempotent ensure methods for declarative object management. Each method checks current state with DISPLAY, then DEFINE, ALTER, or no-ops as needed. Returns an ensure result indicating what action was taken. The queue manager variant is a special singleton (no name, no DEFINE). Only changed attributes are sent in ALTER commands, preserving ALTDATE/ALTTIME audit timestamps.
Mapping pipeline
Bidirectional attribute translation between developer-friendly names and native MQSC parameter names. Includes key mapping (attribute names), value mapping (enumerated values), and key-value mapping (combined name+value translations). The mapping tables were bootstrapped from IBM MQ 9.4 documentation and cover all standard MQSC attributes.
Exception hierarchy
Structured error types for transport failures, malformed responses, authentication errors, MQSC command errors, and polling timeouts. All exceptions carry diagnostic context including the full MQ response payload when available.

In the Ruby implementation, the core components map to these types:

  • Session: The main entry point. A single class that owns connection details, authentication, mapping configuration, diagnostic state, and all 148 command methods plus 16 ensure methods and 9 sync methods. Created via Session.new with keyword arguments.
  • Command methods: Instance methods on Session (e.g. display_queue, define_qlocal, delete_channel). Each method is a thin wrapper that calls the internal mqsc_command dispatcher with the correct verb and qualifier.
  • Mapping module: Internal module that handles bidirectional attribute translation using mapping data loaded from a bundled JSON resource. See the mapping pipeline for details.
  • Error classes: A hierarchy under MQ::REST::Admin::Error with specific subclasses (TransportError, CommandError, etc.) for rescue matching.

Request lifecycle

Every MQSC command follows the same path through the system:

Method call (e.g. displayQueue / display_queue)
  → command dispatcher
    → Map request attributes (friendly names → MQSC)
    → Map response parameter names
    → Map WHERE keyword
    → Build runCommandJSON payload
    → Transport POST
    → Parse JSON response
    → Extract commandResponse items
    → Flatten nested objects
    → Map response attributes (MQSC → friendly names)
  → Return result

Build phase

  1. The command method calls the internal dispatcher with the MQSC verb (e.g. DISPLAY), qualifier (e.g. QUEUE), and user-supplied parameters.
  2. If mapping is enabled, request attributes are translated from friendly names to MQSC parameter names via the qualifier's request key map and request value map.
  3. Response parameter names are mapped similarly.
  4. A WHERE clause keyword, if provided, is mapped through the same qualifier key maps.
  5. The runCommandJSON payload is assembled and sent via the transport.

Parse phase

  1. The JSON response is parsed and validated.
  2. Error codes (overallCompletionCode, overallReasonCode, per-item completionCode/reasonCode) are checked. Errors raise a command exception.
  3. The parameters dict is extracted from each commandResponse item.
  4. Nested objects lists (e.g. from DISPLAY CONN TYPE(HANDLE)) are flattened into the parent parameter set.
  5. If mapping is enabled, response attributes are translated from MQSC to friendly names.

In Ruby, the command dispatcher is the private mqsc_command method on Session. Every public command method (e.g. display_queue, define_qlocal) delegates to it with the appropriate verb and qualifier.

The session retains diagnostic state from the most recent command for inspection:

session.display_queue(name: 'MY.QUEUE')

session.last_command_payload    # the Hash sent to MQ
session.last_response_payload   # the parsed Hash response
session.last_http_status        # HTTP status code
session.last_response_text      # raw response body

Transport abstraction

The session object does not make HTTP calls directly. Instead, it delegates to a transport interface that defines a single method for posting JSON payloads:

  • URL: The fully-qualified endpoint URL.
  • Payload: The runCommandJSON request body.
  • Headers: Authentication, CSRF token, and optional gateway headers.
  • Timeout: Per-request timeout duration.
  • TLS verification: Whether to verify server certificates.

The transport returns a response object containing the HTTP status code, response body, and response headers.

The default implementation wraps the language's standard HTTP client. Tests inject a mock transport to avoid network calls, making the entire command pipeline testable without an MQ server.

In Ruby, the transport is defined by a duck-type contract:

# Any object responding to #post_json with this signature
def post_json(url, payload, headers:, timeout_seconds:, verify_tls:)
  # Returns a TransportResponse
end

The default NetHTTPTransport uses net/http. Custom implementations can be injected via the transport: keyword argument for testing or specialized HTTP handling.

For testing, inject a mock transport:

class MockTransport
  attr_reader :calls

  def initialize(responses: [])
    @responses = responses
    @call_index = 0
    @calls = []
  end

  def post_json(url, payload, headers:, timeout_seconds:, verify_tls:)
    @calls << { url: url, payload: payload }
    response = @responses[@call_index]
    @call_index += 1
    response || MQ::REST::Admin::TransportResponse.new(
      status_code: 200,
      body: '{"commandResponse":[]}',
      headers: {}
    )
  end
end

session = MQ::REST::Admin::Session.new(
  'https://localhost:9443/ibmmq/rest/v2', 'QM1',
  credentials: MQ::REST::Admin::BasicAuth.new(username: 'admin', password: 'pass'),
  transport: MockTransport.new
)

This makes the entire command pipeline testable without an MQ server.

Single-endpoint design

All MQSC operations go through a single REST endpoint:

POST /ibmmq/rest/v2/admin/action/qmgr/{qmgr}/mqsc

The runCommandJSON payload specifies the MQSC verb, qualifier, object name, parameters, and response parameters. This design means the library needs exactly one HTTP method and one URL pattern to cover all MQSC commands.

In Ruby, this means every command method on Session ultimately calls the same post_json method on the transport with the same URL pattern. The only variation is the JSON payload content.

Gateway routing

The MQ REST API is available on all supported IBM MQ platforms (Linux, AIX, Windows, z/OS, and IBM i). The library is developed and tested against the Linux implementation.

In enterprise environments, a gateway queue manager can route MQSC commands to remote queue managers via MQ channels — the same mechanism used by runmqsc -w and the MQ Console.

When a gateway queue manager is configured on the session:

  • The URL path targets the remote queue manager: POST /admin/action/qmgr/{TARGET_QM}/mqsc
  • The ibm-mq-rest-gateway-qmgr HTTP header names the local queue manager that routes the command.

When no gateway is configured (the default), no gateway header is sent and the REST API talks directly to the queue manager in the URL. This makes the feature purely additive — existing sessions are unaffected.

Client                     Gateway QM (QM1)              Target QM (QM2)
  │                              │                              │
  │  POST /qmgr/QM2/mqsc        │                              │
  │  Header: gateway-qmgr=QM1   │                              │
  │─────────────────────────────>│   MQSC via MQ channel        │
  │                              │─────────────────────────────>│
  │                              │<─────────────────────────────│
  │<─────────────────────────────│                              │

Prerequisites

  • The gateway queue manager must have a running REST API.
  • MQ channels must be configured between the gateway and target queue managers.
  • A QM alias (QREMOTE with empty RNAME) must map the target QM name to the correct transmission queue on the gateway.

In Ruby, configure gateway routing via a keyword argument:

session = MQ::REST::Admin::Session.new(
  'https://qm1-host:9443/ibmmq/rest/v2',
  'QM2',                                      # target (remote) queue manager
  credentials: MQ::REST::Admin::BasicAuth.new(username: 'mqadmin', password: 'mqadmin'),
  gateway_qmgr: 'QM1'                         # local gateway queue manager
)

Zero dependencies

The gem uses only the Ruby standard library:

  • net/http for HTTP
  • json for JSON
  • openssl for TLS/mTLS
  • base64 for Basic auth encoding

Ensure pipeline

See ensure for details on the idempotent create-or-update pipeline.

Sync pipeline

See sync for details on the synchronous polling pipeline.