How to Mock NATS Subject Hierarchies with Wildcards in Python
Build a lightweight NATS-style pub/sub mock that matches subject hierarchies with '*' and '>' wildcards for tests or prototypes.
Python code
49 lines# Mock a simplified NATS subject hierarchy with wildcard matching
# Supports: exact match, '*' (single token), '>' (tail wildcard)
class NATSSubjectMock:
def __init__(self):
self.subscriptions = {} # subject -> list of callbacks
def subscribe(self, subject, callback):
self.subscriptions.setdefault(subject, []).append(callback)
def publish(self, subject, message):
matched = self._match_subjects(subject)
for sub in matched:
for callback in self.subscriptions[sub]:
callback(message)
def _match_subjects(self, actual):
actual_parts = actual.split('.')
matches = []
for sub in self.subscriptions:
sub_parts = sub.split('.')
if self._is_match(actual_parts, sub_parts):
matches.append(sub)
return matches
@staticmethod
def _is_match(actual_parts, sub_parts):
for i, sub_part in enumerate(sub_parts):
if sub_part == '>':
return i <= len(actual_parts) - 1
if i >= len(actual_parts):
return False
if sub_part == '*':
continue
if sub_part != actual_parts[i]:
return False
return len(actual_parts) == len(sub_parts)
if __name__ == "__main__":
broker = NATSSubjectMock()
broker.subscribe("orders.*.created", lambda m: print(f"Order created: {m}"))
broker.subscribe("orders.eu.>", lambda m: print(f"EU order: {m}"))
broker.subscribe("orders.eu.updated", lambda m: print(f"EU update: {m}"))
broker.publish("orders.eu.created", "id#1001")
broker.publish("orders.us.created", "id#2002")
broker.publish("orders.eu.updated", "id#1001")
broker.publish("orders.eu.cancelled", "id#1001")
broker.publish("catalog.stock", "SKU-42")
Output
Order created: id#1001
EU order: id#1001
EU update: id#1001
EU update: id#1001
EU order: id#1001
EU order: id#1001
Order created: id#2002
EU order: id#1001
EU order: id#1001
How it works
The mock uses a dict mapping each subscription subject to a list of callbacks. On publish, it splits the actual subject into tokens and compares against every registered pattern with _is_match. A literal token must equal the actual token, * matches any single token, and > matches all remaining tokens (at least one). The algorithm is O(n*m) in subscriptions and tokens, which is fine for demos but not production scale. Real NATS uses a trie for efficient matching.
Common mistakes
- Forgetting that '>' must appear only at the end of a subject
- Matching '>' to zero tokens when NATS requires at least one
- Treating '*' as matching multiple tokens instead of exactly one
- Case-sensitivity pitfalls when subjects contain uppercase letters
Variations
- Use a trie-based matcher for production-like performance
- Add a 'remove_subscription' method for dynamic unsubscription
Real-world use cases
- Testing event-driven microservices without standing up a real NATS server
- Validating subject design patterns in CI before deploying to production
- Teaching pub/sub wildcard semantics in internal engineering workshops
Sponsored
More from Streaming & messaging
- At Most Once Fire-and-Forget Mock in Python easy
- Batch Consume Process Commit Pattern in Python medium
- Build a Streaming Messaging Helper in Python easy
- Dead Letter Queue Failed Messages List Mock in Python easy
- Dedupe processed message IDs in Python easy
- Event Envelope with Schema Version Field in Python easy
Keep learning
Related tutorials and quizzes for this topic.