Trooba
Fast isomorphic lightweight framework to build pipelines for request/response, stream/response, request/response and stream/stream use-cases
Install / Use
/learn @trooba/TroobaREADME
"Trooba" [tru:ba'] means "Pipe" in Russian and it is not a pipe.
What is it?
Trooba a fast isomorphic lightweight pipeline framework from eBay. Trooba can build pipelines for request/response, stream/response, request/response and stream/stream use-cases spanning from a browser to a front-end app and further to a backend services.
Try it online to see what it can do for you as well as read about ideas behind it here
It uses a stateless generic pipeline/bus used to route multiple requests in "parallel" without any conflicts. The contextual information is passed along with the message.
Trooba does not dictate specific data structures that should be used for request/response/messages/stream objects. It assumes basic requirements and leaves everything else to the implementor of the transport.
What is it not?
It is not another http based server framework like express, koa or hapi. It can be used to build a pipline for those as it is protocol independent and allows to specify any transport one needs. For example see examples
What can it do for you?
- Define a pipeline of handlers and execute it
- The handlers are executed in order they were added.
- Define a service client:
- The request object is passed from client through a set of handlers before getting to the transport handler.
- The response object is passed in the reverse order of handlers from transport handler to the client.
- Define a service:
- The request object is passed from transport through a set of handlers before getting to the controller
- The response object is passed in the reversed order from the controller defined by the user through a set of handlers to the transport of the service.
- Set transport handler or a set of them in the fallback order (http, soap, grpc, mock or custom) for a pipeline.
- Inject API that can be returned by pipe.build().create(customApiName) method, mostly useful to provide a protocol specific API, for example, gRPC can expose API defined in proto file as client and service API or soap API defined by wsdl.
- It supports request/response, pub/sub or a mix of these modes or you can use it as a one-way or bidirectional message bus.
- You can link different pipelines together in definition or on-the-fly.
- You can trace the route to troubleshoot any problems or learn some complex pipeline.

Get Involved
- Contributing: Pull requests are welcome!
- Read
CONTRIBUTING.mdand check out our bite-sized and help-wanted issues - Submit github issues for any feature enhancements, bugs or documentation problems
- Read
- Support: Join our gitter chat to ask questions to get support from the maintainers and other Trooba developers
- Questions/comments can also be posted as github issues
Install
npm install trooba --save
Usage
Client example
Example on how the pipe for http calls can be configured. The middleware used is for demonstration and is not provided out of the box except for the transport and need to be built. You can try simpler working examples mentioned down this page.
require('trooba')
.use('circuit')
.use('retry')
.use('logging')
.use('tracing')
.use('security')
.use('analytics')
.use('trooba-http-transport', {
protocol: 'http:',
hostname: 'www.google.com',
connectTimeout: 100,
socketTimeout: 1000
})
.build() // build the pipe
.create('client:default') // create client
.request({ // initiate a request
q: 'nike',
method: 'GET'
}, function (err, response) {// get the results
console.log(err || response.body.toString());
});
Service example
Example on how one can configure a service endpoint. The middleware used is for demonstration and is not provided out of the box except for the transport and needs to be built. You can try simpler working examples mentioned down this page.
require('trooba')
.use('trooba-grpc-transport', {
port: port,
hostname: 'localhost',
proto: Grpc.load(require.resolve('./path/to/hello.proto'))
})
.use('tracing')
.use('rate-limiter')
.use('security')
.use('analytics')
.use('router')
.build() // build the pipe
.create('service:default') // create service
.listen();
Building a pipe
var pipe = require('trooba')
// adding handler to collect metrics
.use(function (pipe) {
var start;
pipe.on('request', function (request, next) {
start = Date.now();
next(); // continue with request
})
pipe.on('response', function (response, next) {
console.log('call time is', Date.now() - start, 'ms');
next(); // continue with reponse flow
})
})
.use(retry, 2); // retry 2 times, see example of retry handler below
Adding a transport
// setting transport or you can use module reference
pipe.use(function transport(pipe) {
// hook to request
pipe.on('request', function (request) {
// respond
pipe.respond('Hello ' + request.name);
})
})
Make a request
Injecting static context if any needed or this can be skipped.
pipe = pipe.build()
At this point the pipe becomes re-usable between multiple "parallel" requests.
Make a request
pipe.create()
.request({
name: 'John'
})
.on('error', console.error)
.on('response', console.log);
Or you can do it with a callback style
pipe.create()
.request({
name: 'John'
}, console.log);
Note: Though pipe API to add hooks looks like event emitter, it does not allow multiple hooks and will throw error if one attempts to add a hook for the event that already has it. If you really need to support multiple listeners, you can add an event dispatcher as a hook.
Creating custom pipeline protocols
The request and response hooks used above are just event names and a developer is not limited to them.
One can create different protocols using different names. Trooba framework just provides default protocol based on request/response pattern. One can mix custom events in the default pipeline or create completely new one if needed.
Adding custom event
Let's assume we want to update global config for some handlers.
// setting transport or you can use module reference
let config;
pipe.use(function config(pipe) {
// hook to config message
pipe.on('config', function (cfg) {
config = cfg;
});
})
Broadcast configuration
pipe.create()
.send({
type: 'config',
flow: Types.REQUEST,
ref: {
some: 'config'
}
});
Trooba API
use(handler[, config])- adds a handler to the pipelinehandler- afunction handler(pipe) {}or another pipe to join into this pipe.configis a config object for the handler
build([context])- creates a pipe and returns a generic pipe object.set(name, value)- used set system value to the context. The name is prefixed with '$' that prevents it from being propagated beyond the current pipe context boundaries.get(name)- is used to get system value from the context.
Pipe API
The pipe object is passed to all handlers and transport during initialization whenever new context is created via trooba.build(context) or pipe.create(context) call.
create([context], [customApiImpl])- creates a pipeline with new context or clones from the existing one if any present. The method is mandatory to initiate a new flow, otherwise the subsequent call will fail.contextis a context object to be used in request/message flow.customApiImplis a name for a specific API implementation. It allows to inject custom API provided by one of the handlers that needs to be returned instead of the generic pipe interface.
contextis an object available to all handlers/transport in the same request/response flow. One can use it to store data that needs to be shared between handlers if needed. The values in the context that have their names started with '$' will not be propagated beyond the pipe boundaries. To access context one can use pipe.context;storeis a storage for properties specific to the given pipe point. This is useful to share things between different requests. One can store there objects that needs to be initialized only once.
Trooba.use(function (pipe, config) {
if (!pipe.store.obj) {
// do it only once
