Client Usage
Learn how to use the type-safe AMQP client to publish messages.
Creating a Client
Create a type-safe client from your contract. TypedAmqpClient.create(...) returns ResultAsync<TypedAmqpClient, TechnicalError> — await yields a Result, which you unwrap (_unsafeUnwrap()) or pattern-match before using:
import { TypedAmqpClient } from "@amqp-contract/client";
import { contract } from "./contract";
const client = (
await TypedAmqpClient.create({
contract,
urls: ["amqp://localhost"],
})
)._unsafeUnwrap();Default Publish Options
Configure default publish options that apply to all messages published by the client:
const client = (
await TypedAmqpClient.create({
contract,
urls: ["amqp://localhost"],
defaultPublishOptions: {
priority: 5,
headers: { "x-app-version": "1.0.0" },
},
})
)._unsafeUnwrap();Default publish options can be overridden by options passed to individual publish calls.
By default, messages are persistent for message durability, but this can be overridden by explicitly setting persistent: false in defaultPublishOptions when creating the client, or in the options passed to the publish method when publishing messages.
Publishing Messages
Publish messages with full type safety and explicit error handling:
const result = await client.publish("orderCreated", {
orderId: "ORD-123",
customerId: "CUST-456",
amount: 99.99,
items: [{ productId: "PROD-A", quantity: 2 }],
});
result.match(
() => console.log("✅ Published"),
(error) => console.error("❌ Failed:", error.message),
);Type Safety
The client enforces:
- ✅ Valid publisher names - Only publishers from contract
- ✅ Message schema - Messages must match schema
- ✅ Autocomplete - Full IDE support
- ✅ Explicit errors - Returned via
Resulttype
// ❌ TypeScript error: 'unknownPublisher' not in contract
const result = await client.publish('unknownPublisher', { ... });
// ❌ TypeScript error: missing required field
const result = await client.publish('orderCreated', {
customerId: 'CUST-456',
});
// ❌ Runtime validation error returned in Result
const result = await client.publish('orderCreated', {
orderId: 123, // should be string
customerId: 'CUST-456',
amount: 99.99,
});
result.match(
() => console.log('Published'),
(error) => console.error('Validation failed:', error),
);Publishing Options
Custom Routing Key
Override the routing key for specific messages:
const result = await client.publish(
"orderCreated",
{ orderId: "ORD-123", amount: 99.99 },
{ routingKey: "order.created.urgent" },
);Message Properties
Set AMQP message properties:
const result = await client.publish(
"orderCreated",
{ orderId: "ORD-123", amount: 99.99 },
{
options: {
persistent: false,
priority: 10,
headers: { "x-request-id": "req-123" },
},
},
);Publishing with Headers
When your message schema defines a headers schema, pass headers via the options.headers property:
const result = await client.publish(
"orderCreated",
{ orderId: "ORD-123", amount: 99.99 },
{
headers: {
correlationId: "550e8400-e29b-41d4-a716-446655440000",
priority: "high",
tenantId: "tenant-42",
},
},
);Headers are validated by the consumer at runtime using the headers schema defined in defineMessage. On the publish side, headers are passed as raw AMQP message properties — make sure to match the expected schema to avoid consumer-side validation errors.
Connection Management
Closing the Connection
await client.close();Error Handling
Errors are returned via Result types, not thrown:
import { MessageValidationError, TechnicalError } from "@amqp-contract/client";
import { match, P } from "ts-pattern";
const result = await client.publish("orderCreated", {
orderId: "ORD-123",
amount: 99.99,
});
result.match(
() => console.log("✅ Published"),
(error) =>
match(error)
.with(P.instanceOf(MessageValidationError), (err) =>
console.error("Validation failed:", err.issues),
)
.with(P.instanceOf(TechnicalError), (err) => console.error("Technical error:", err.message))
.exhaustive(),
);Error Types:
MessageValidationError- Schema validation failedTechnicalError- Network or runtime failures
Note: Programming errors (like invalid publisher name) still throw exceptions, since TypeScript should catch those at compile-time.
Complete Example
import { TypedAmqpClient } from "@amqp-contract/client";
import { MessageValidationError, TechnicalError } from "@amqp-contract/client";
import { match, P } from "ts-pattern";
import { contract } from "./contract";
async function main() {
let client;
try {
client = (
await TypedAmqpClient.create({
contract,
urls: ["amqp://localhost"],
})
)._unsafeUnwrap();
const result = await client.publish("orderCreated", {
orderId: "ORD-123",
customerId: "CUST-456",
amount: 99.99,
items: [{ productId: "PROD-A", quantity: 2 }],
});
result.match(
() => console.log("✅ Message published"),
(error) =>
match(error)
.with(P.instanceOf(MessageValidationError), (err) =>
console.error("❌ Validation failed:", err.issues),
)
.with(P.instanceOf(TechnicalError), (err) =>
console.error("❌ Technical error:", err.message),
)
.exhaustive(),
);
} catch (error) {
console.error("Unexpected error:", error);
} finally {
await client?.close();
}
}
main();Next Steps
- Learn about Worker Usage
- Explore Defining Contracts
- Check out Examples