@amqp-contract/client
Type-safe AMQP client for publishing messages.
Installation
bash
pnpm add @amqp-contract/clientMain Exports
TypedAmqpClient.create
Creates a type-safe AMQP client from a contract and automatically connects to RabbitMQ.
Signature:
typescript
static async create<TContract>(
options: CreateClientOptions<TContract>
): Promise<TypedAmqpClient<TContract>>Example:
typescript
import { TypedAmqpClient } from '@amqp-contract/client';
import { contract } from './contract';
const client = await TypedAmqpClient.create({
contract,
connection: 'amqp://localhost'
});Parameters:
options- Configuration object:contract- Contract definition created withdefineContractconnection- AMQP connection URL (string) or connection options (Options.Connect)
Returns: Promise that resolves to a type-safe AMQP client
TypedAmqpClient API
connect
Connects the client to RabbitMQ.
Note: When using TypedAmqpClient.create(), this method is called automatically. This method is private and not exposed in the public API.
publish
Publishes a message with type safety and validation.
Signature:
typescript
async publish<K extends keyof Publishers>(
publisher: K,
message: InferredMessage<Publishers[K]>,
options?: PublishOptions
): Promise<void>Example:
typescript
await client.publish('orderCreated', {
orderId: 'ORD-123',
amount: 99.99,
});Parameters:
publisher- Publisher name (from contract)message- Message object (typed based on schema)options- Optional publish optionsroutingKey- Override the routing keypersistent- Message persistence (default:false)mandatory- Return message if not routed (default:false)immediate- Return message if no consumers (default:false)priority- Message priority (0-9)expiration- Message TTL in millisecondscontentType- Content type (default:'application/json')contentEncoding- Content encodingheaders- Custom headers objectcorrelationId- Correlation IDreplyTo- Reply-to queuemessageId- Message IDtimestamp- Message timestamptype- Message typeuserId- User IDappId- Application ID
Throws:
ZodError(or equivalent) if message fails schema validationErrorif publishing fails
close
Closes the client channel and connection.
Signature:
typescript
async close(): Promise<void>Example:
typescript
await client.close();Types
CreateClientOptions
typescript
interface CreateClientOptions<TContract> {
contract: TContract;
connection: string | Options.Connect;
}PublishOptions
typescript
interface PublishOptions {
routingKey?: string;
persistent?: boolean;
mandatory?: boolean;
immediate?: boolean;
priority?: number;
expiration?: string;
contentType?: string;
contentEncoding?: string;
headers?: Record<string, any>;
correlationId?: string;
replyTo?: string;
messageId?: string;
timestamp?: number;
type?: string;
userId?: string;
appId?: string;
}Basic Example
typescript
import { TypedAmqpClient } from '@amqp-contract/client';
import { contract } from './contract';
async function main() {
// Create client (automatically connects)
const client = await TypedAmqpClient.create({
contract,
connection: 'amqp://localhost'
});
// Publish message
await client.publish('orderCreated', {
orderId: 'ORD-123',
customerId: 'CUST-456',
amount: 99.99,
items: [
{ productId: 'PROD-A', quantity: 2 },
],
createdAt: new Date().toISOString(),
});
console.log('Message published!');
// Cleanup
await client.close();
}
main();Publishing with Options
typescript
// Persistent message
await client.publish('orderCreated', message, {
persistent: true,
});
// Custom routing key
await client.publish('orderCreated', message, {
routingKey: 'order.created.urgent',
});
// With priority and headers
await client.publish('orderCreated', message, {
persistent: true,
priority: 10,
headers: {
'x-request-id': 'req-123',
'x-source': 'api',
},
});
// With expiration (TTL)
await client.publish('orderCreated', message, {
expiration: '60000', // 60 seconds
});Error Handling
typescript
try {
await client.publish('orderCreated', message);
} catch (error) {
if (error.name === 'ZodError') {
// Schema validation error
console.error('Invalid message:', error.issues);
} else {
// Other error (network, etc.)
console.error('Publishing failed:', error);
}
}Connection Management
typescript
// Create connection with options
const client = await TypedAmqpClient.create({
contract,
connection: {
protocol: 'amqp',
hostname: 'localhost',
port: 5672,
username: 'guest',
password: 'guest',
heartbeat: 30,
}
});
// Or use a connection string
const client = await TypedAmqpClient.create({
contract,
connection: 'amqp://guest:guest@localhost:5672?heartbeat=30'
});
// Use client...
// Cleanup - closes both channel and connection
await client.close();Multiple Clients
You can create multiple clients from the same or different contracts:
typescript
const orderClient = await TypedAmqpClient.create({
contract: orderContract,
connection: 'amqp://localhost',
});
const paymentClient = await TypedAmqpClient.create({
contract: paymentContract,
connection: 'amqp://localhost',
});
// Use both clients
await orderClient.publish('orderCreated', orderMessage);
await paymentClient.publish('paymentProcessed', paymentMessage);
// Cleanup
await orderClient.close();
await paymentClient.close();Type Inference
The client provides full type inference for publisher names and message schemas:
typescript
// TypeScript knows available publishers
client.publish('orderCreated', ...); // ✅ Valid
client.publish('unknownPublisher', ...); // ❌ TypeScript error
// TypeScript knows message shape
client.publish('orderCreated', {
orderId: 'ORD-123', // ✅ Required field
amount: 99.99, // ✅ Required field
});
client.publish('orderCreated', {
orderId: 'ORD-123', // ❌ Missing 'amount'
});
client.publish('orderCreated', {
orderId: 123, // ❌ Wrong type (should be string)
amount: 99.99,
});See Also
- Contract API - Defining contracts
- Worker API - Consuming messages
- Client Usage Guide