Message Structure Overview¶
Understanding how BunnyFarm messages are structured is key to using the library effectively. This section covers the anatomy of a BunnyFarm message and how the DSL components work together.
Message Class Anatomy¶
A BunnyFarm message class consists of several key components:
class OrderMessage < BunnyFarm::Message
# 1. Fields DSL - Define data structure
fields :order_id, :total,
{ customer: [:name, :email] },
{ items: [:id, :qty] }
# 2. Actions DSL - Define available operations
actions :validate, :process_payment, :ship, :cancel
# 3. Action Methods - Business logic
def validate
# Validation logic here
success!
successful?
end
def process_payment
# Payment processing logic
success!
successful?
end
# 4. Helper Methods (private)
private
def validate_customer
# Helper logic
end
end
DSL Components¶
Fields DSL¶
The fields
DSL defines the expected data structure for your messages:
- Simple fields: Basic data types like strings, numbers, booleans
- Nested objects: Complex data structures with sub-fields
- Arrays: Lists of items or objects
Actions DSL¶
The actions
DSL defines the operations your message can perform:
- Each action becomes a routable method
- Actions map to routing keys:
MessageClass.action
- Must implement corresponding methods
Instance Structure¶
When a message is instantiated, it contains several important instance variables:
@items¶
Validated and structured data extracted from the raw JSON based on your fields definition.
@elements¶
Raw JSON data as received from the message broker.
@payload¶
The original JSON string as received from RabbitMQ.
@errors¶
Array of error messages accumulated during processing.
Data Flow¶
The message goes through several stages:
- JSON Input - Raw message data from RabbitMQ
- Parse & Validate - Extract fields using DSL definition
- Route Action - Call method based on routing key
- Execute Logic - Run business logic in action method
- ACK/NACK - Acknowledge to RabbitMQ based on success/failure
Access Methods¶
BunnyFarm provides several ways to access and manipulate message data:
Hash-like Access¶
JSON Serialization¶
Field Inspection¶
State Management¶
Messages track their processing state throughout the lifecycle:
Success States¶
Failure States¶
Publishing¶
Best Practices¶
1. Design Clear Field Structures¶
# Good: Clear, hierarchical structure
fields :order_id, :amount,
{ customer: [:name, :email, :phone] },
{ billing_address: [:street, :city, :state, :zip] }
# Avoid: Flat, unclear structure
fields :order_id, :customer_name, :customer_email,
:billing_street, :billing_city # ... too flat
2. Use Meaningful Action Names¶
# Good: Descriptive action names
actions :validate_order, :process_payment, :ship_order, :send_confirmation
# Avoid: Generic action names
actions :process, :handle, :do_work
3. Implement Proper Error Handling¶
def process_payment
return failure("Missing payment info") unless payment_present?
return failure("Invalid amount") unless valid_amount?
charge_result = payment_gateway.charge(@items[:amount])
if charge_result.success?
success!
else
failure("Payment failed: #{charge_result.error}")
end
successful?
end
4. Keep Methods Focused¶
Each action method should have a single, clear responsibility:
def validate_order
validate_customer_info
validate_items
validate_shipping_address
success! if errors.empty?
successful?
end
private
def validate_customer_info
failure("Customer name required") if @items[:customer][:name].blank?
failure("Customer email required") if @items[:customer][:email].blank?
end
Next Steps¶
Now that you understand message structure, explore:
- Fields DSL - Detailed guide to defining data structures
- Actions DSL - Complete actions DSL reference
- Instance Methods - All available instance methods
- Configuration - Message configuration options