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(orverbQualifierin camelCase languages), mapping directly to MQSC commands. For example,DISPLAY QUEUEbecomesdisplay_queue/displayQueue, andDEFINE QLOCALbecomesdefine_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/ALTTIMEaudit 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 Rust implementation, the core components map to these modules:
MqRestSession(session.rs): The main entry point. Owns authentication, base URL construction, request/response handling, and diagnostic state. Constructed viaMqRestSessionBuilder.- Command methods (
commands.rs): Provides ~148 MQSC command methods. Each method is a thin wrapper that callsmqsc_command()with the correct command verb and qualifier. - Ensure methods (
ensure.rs): Provides 16 idempotentensure_*methods for declarative object management.ensure_qmgr()is a special singleton variant (no name, no DEFINE). - Mapping pipeline (
mapping.rs,mapping_data.rs): Bidirectional attribute translation between Rustsnake_casenames and native MQSC parameter names. See the mapping pipeline for details. - Error types (
error.rs): Structured error types usingthiserror.MqRestErroris the top-level enum with variants for each failure mode.
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¶
- The command method calls the internal dispatcher with the MQSC verb (e.g.
DISPLAY), qualifier (e.g.QUEUE), and user-supplied parameters. - 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.
- Response parameter names are mapped similarly.
- A
WHEREclause keyword, if provided, is mapped through the same qualifier key maps. - The
runCommandJSONpayload is assembled and sent via the transport.
Parse phase¶
- The JSON response is parsed and validated.
- Error codes (
overallCompletionCode,overallReasonCode, per-itemcompletionCode/reasonCode) are checked. Errors raise a command exception. - The
parametersdict is extracted from eachcommandResponseitem. - Nested
objectslists (e.g. fromDISPLAY CONN TYPE(HANDLE)) are flattened into the parent parameter set. - If mapping is enabled, response attributes are translated from MQSC to friendly names.
In Rust, the command dispatcher is the mqsc_command() method on
MqRestSession. 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(Some("MY.QUEUE"), None, None, None)?;
session.last_command_payload(); // the JSON sent to MQ
session.last_response_payload(); // the parsed JSON 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
runCommandJSONrequest 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 Rust, the transport is defined by the MqRestTransport trait:
pub trait MqRestTransport: Send + Sync {
fn post_json(
&self,
url: &str,
payload: &serde_json::Value,
headers: &HashMap<String, String>,
timeout_seconds: Option<f64>,
verify_tls: bool,
) -> Result<TransportResponse, MqRestError>;
}
The default implementation, ReqwestTransport, wraps the reqwest blocking
client.
For testing, inject a mock transport:
use mq_rest_admin::{MqRestSession, Credentials, MqRestTransport, TransportResponse};
struct MockTransport;
impl MqRestTransport for MockTransport {
fn post_json(
&self, _url: &str, _payload: &serde_json::Value,
_headers: &HashMap<String, String>,
_timeout: Option<f64>, _verify: bool,
) -> Result<TransportResponse, MqRestError> {
Ok(TransportResponse {
status_code: 200,
text: r#"{"commandResponse": []}"#.into(),
headers: HashMap::new(),
})
}
}
let session = MqRestSession::builder()
.rest_base_url("https://localhost:9443/ibmmq/rest/v2")
.qmgr_name("QM1")
.credentials(Credentials::Basic {
username: "admin".into(),
password: "passw0rd".into(),
})
.transport(Box::new(MockTransport))
.build()?;
This makes the entire command pipeline testable without an MQ server.
Single-endpoint design¶
All MQSC operations go through a single REST endpoint:
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 Rust, this means every command method on MqRestSession 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-qmgrHTTP 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 Rust, configure gateway routing via the builder:
let session = MqRestSession::builder()
.rest_base_url("https://qm1-host:9443/ibmmq/rest/v2")
.qmgr_name("QM2") // target (remote) queue manager
.credentials(Credentials::Ltpa {
username: "mqadmin".into(),
password: "mqadmin".into(),
})
.gateway_qmgr("QM1") // local gateway queue manager
.build()?;
Minimal dependencies¶
The library depends on:
- reqwest — HTTP client (blocking, rustls-tls)
- serde / serde_json — JSON serialization
- thiserror — Error type derivation
- base64 — CSRF token encoding
No other runtime dependencies are required.
Generated command methods¶
The ~148 command methods in commands.rs are generated from the command
definitions in mapping-data.json. Each method:
- Accepts
name,request_parameters,response_parameters, andwhere_clause(for DISPLAY commands). - Calls
self.mqsc_command()with the correct verb and qualifier. - Returns
Vec<HashMap<String, Value>>for DISPLAY commands,()for others.
Queue manager commands (display_qmgr, display_qmstatus, etc.)
have singleton helpers that return Option<HashMap<String, Value>>
instead of a list.
Ensure pipeline¶
See ensure for details on the idempotent create-or-update pipeline.
Sync pipeline¶
See sync for details on the synchronous polling pipeline.