@Echoes() and @EchoRequest() or @EchoEvent() decorators, you can easily create handlers for both synchronous requests and asynchronous events.
Standalone core and Orion integration
@orion-js/echoes is framework-independent. Its required dependency graph does not include
@orion-js/schema, @orion-js/services, @orion-js/http, @orion-js/logger, or any other Orion
runtime package.
Orion applications keep their existing behavior through @orion-js/echoes-orion. It connects
Echoes to Orion schemas, dependency injection, async logger context, HTTP routes, and Orion error
classes:
@orion-js/components do not need this explicit import because Components
installs the adapter automatically.
Schema execution is still runtime behavior, not just TypeScript inference. For every handler,
Echoes cleans and validates
params before calling resolve, then cleans returns before
sending the result. The Orion adapter delegates those operations to @orion-js/schema, so
existing custom cleaners, defaults, validations, and ValidationError values keep working.Creating Echo Controllers
An echoes controller is a class decorated with@Echoes() that contains methods decorated with @EchoRequest() or @EchoEvent():
Echo Request Handlers
Use the@EchoRequest() decorator with the createEchoRequest() function to define methods that handle synchronous requests from other services:
Echo Event Handlers
Use the@EchoEvent() decorator with the createEchoEvent() function to define methods that process asynchronous events:
Event Decorator Options
ThecreateEchoEvent() function accepts options similar to createEchoRequest():
Making Requests
To make a request to another service:Publishing Events
To publish an event for other services to consume:Starting the Echoes Service
To enable echoes in your application, you need to configure and start the echoes service:Using Echoes without Orion
A standalone service can use a SimpleSchema-compatible object directly. Echoes recognizes objects withclean() and validate() methods and executes both at runtime. typedEchoesSchema() adds
the value type when the schema library does not expose it in a form TypeScript can infer:
kafkajs for
Kafka, or @orion-js/pulse with its MongoDB peer dependency for Pulse. A service that only uses
synchronous requests loads neither event transport.
Incremental migration from Kafka to Pulse
Echoes can listen through Kafka and Pulse at the same time while publishing through exactly one transport. This allows the migration to happen in three independent deployments, without dual-publishing an event. Install Pulse and its MongoDB peer dependency in the application:1. Prepare every listener
Keep the existing top-level Kafka configuration and add Pulse underevents. Deploy this version
to every instance before changing any publisher:
publish() still sends only to Kafka.
The event handler API does not change.
The Pulse transport uses a MongoDB application pool of at most five connections per service
instance by default. Set events.pulse.maxPoolSize when a specific service needs a different
limit.
2. Switch publishers
Once every listener is running the dual-consumer configuration, change onlypublishTo:
publishTo can also come from an environment flag:
3. Remove Kafka consumption
After every publisher uses Pulse and Kafka has no pending events for the service, stop consuming from Kafka:client, consumer, and producer options can then be removed from that application.
If only Pulse is configured, Echoes defaults both consumption and publishing to Pulse.
Pulse is an optional peer dependency and is loaded only when configured. Applications that stay on
Kafka do not need to install or initialize it.
Error Handling
Echoes automatically handles errors in request and event handlers:Custom Error Types
Orionjs handles special error types appropriately:- UserError: For expected application errors
- ValidationError: For data validation errors
Type Safety
Using TypeScript with schema inference, you can ensure type safety for your echo handlers:Best Practices
- Organize by Domain: Group related echo handlers in the same controller class.
-
Leverage Dependency Injection: Use
@Inject(() => Service)to access repositories and services. - Keep Methods Focused: Each echo handler should have a clear, single responsibility.
- Use Strong Typing: Define parameter and return types with schemas and infer TypeScript types.
- Handle Errors Gracefully: Catch and properly categorize errors.
- Idempotent Handlers: Design event handlers to be idempotent (safe to process the same event multiple times).
- Timeout Configuration: Set appropriate timeouts for requests based on expected execution time.
- Security: Use the shared key to secure inter-service communication.
- Service Discovery: Keep the service registry updated when adding new services.
- Monitoring: Implement proper logging and monitoring for echo handlers.