14 Building Node.js Clients and Servers
This chapter introduces how to build Node.js RPC clients and servers with Apache Thrift, explaining the Node-specific asynchronous programming model and how Thrift’s transports and protocols map to it. It contrasts TCP for lean, high-performance RPC with HTTP[S] for integration and security concerns, and outlines the supported transports (such as TBufferedTransport and TFramedTransport) and protocols (TBinaryProtocol, TCompactProtocol, TJSONProtocol). Using a simple “hello world” IDL as a running example, the chapter positions Node.js as a full-featured Thrift platform and sets up the progression from basics to more advanced features.
The core walkthrough covers generating client/server stubs with the Thrift compiler, implementing a server by providing a handler whose methods complete via a result callback, and creating a server with configurable transport/protocol settings. It emphasizes Node.js’s EventEmitter pattern: servers and connections emit events like error, connect, close, and timeout, and robust code should always subscribe to error to avoid crashes. On the client side, createConnection immediately initiates the socket; after the connect event, createClient binds service stubs to the connection and methods are invoked asynchronously via callbacks. The chapter also clarifies connection options (retries, delays, timeouts) and explains that in an asynchronous environment, errors are surfaced through callbacks and events rather than traditional stack-based exceptions.
Building on the basics, the chapter integrates the Q promise library so every RPC call returns a promise in addition to supporting callbacks, enabling state inspection (pending/fulfilled/rejected), chaining, aggregation with Q.all, and structured cleanup via finally. It then demonstrates multiplexing to host multiple services over a single connection using a MultiplexedProcessor on the server and a Multiplexer on the client, noting that multiplexed endpoints require multiplex-aware clients. Finally, a richer TradeHistory example shows practical IDL design in action—enums, typedefs, structs, unions, collections (set, map, list), declared exceptions, and default values—along with realistic Node.js server and client implementations that return data or throw declared errors. The overall guidance stresses clear interface design and Node-focused patterns for building reliable, efficient Thrift systems.
Summary
With the Google V8 JavaScript engine at its core, Node.js has become a popular and performant platform for many organizations building distributed applications, particularly those needing to leverage the skills of their existing JavaScript developers. Apache Thrift makes it possible for Node.js applications to support high performance Web clients while interacting with a range of backend services written in almost any language.
Most of the Apache Thrift features exposed to users, particularly those used in this chapter, are documented in the source with JavaDoc. Building the source in thrift/lib/nodejs will create html documentation from the source comments, you can of course always read them directly too.
This chapter covered:
- Building Node.js TSocket compatible servers
- Multiplexing multiple services over a single connection
- Using the Q library for asynchronous operations
- Proper asynchronous error management in Apache Thrift Node.js
- How to code full featured Apache Thrift interfaces in Node.js
FAQ
How do I generate Node.js client and server stubs from a Thrift IDL?
Install Node.js and the thrift package (npm install thrift), then run the Thrift compiler with thrift -gen js:node yourfile.thrift. The compiler creates a gen-nodejs directory containing one file per service (for example, helloSvc.js) and a types file (for example, hello_types.js) for user-defined structs, enums, unions, etc.What are the basic steps to build a simple TCP Thrift server in Node.js?
- require('thrift') and the generated service module- Implement a handler object with one function per RPC; each function uses the signature (...args, callback) and must call callback(error, result)
- Choose protocol/transport in options (often TBinaryProtocol + TBufferedTransport)
- Create the server with thrift.createServer(Service, handler, options)
- Register an 'error' event handler to avoid crashes
- Start listening with server.listen(port)
How do I write a Node.js Thrift client and make an RPC call?
- Create a connection with thrift.createConnection(host, port, { protocol, transport, ... })- Add listeners for 'error' and 'connect' events
- On 'connect', create a client with thrift.createClient(Service, connection)
- Invoke methods with client.method(args..., function(err, result) { ... })
- Close when done via connection.end()
Which protocols and transports are available in Node.js Thrift, and what are the defaults?
Protocols: TBinaryProtocol, TCompactProtocol, TJSONProtocol. Transports (layered over TCP): TBufferedTransport, TFramedTransport. Defaults, if unspecified: TBinaryProtocol and TBufferedTransport. Framing is not required by Node.js servers unless interoperating with components that demand it.What connection options and events should I know about on the client?
Connect options include protocol, transport, max_attempts, retry_max_delay, connect_timeout, and timeout. Connection emits: 'connect' (ready), 'close', 'timeout' (if set), and 'error' (the only one that passes an Error object). The connection attempts to open immediately upon creation.How are errors handled asynchronously for Node.js Thrift clients and servers?
- RPC-level errors (including exceptions declared in IDL) arrive in the per-call callback’s first parameter (err) or as promise rejections- Network/low-level issues emit an 'error' event on the connection (client) or server (server-side)
- You should handle both: check err in callbacks (or promise catch/fail) and register 'error' handlers on connection/server to prevent unhandled exceptions
Can I use promises with Node.js Thrift clients, and how?
Yes. Every RPC method accepts an optional callback and also returns a promise. With the Q library (npm install q), you can inspect state (isPending, isFulfilled, isRejected), chain results via then(onFulfilled, onRejected), aggregate arrays of promises with Q.all, handle errors with fail/catch, and run cleanup in finally. You can mix callbacks and promises, but typically use one style consistently.What is service multiplexing and when should I use it?
Multiplexing lets one TCP port host multiple Thrift services. Server side: create a thrift.MultiplexedProcessor, register each Service.Processor with a service key, then start a multiplex server with thrift.createMultiplexServer(processor, options). Client side: create a thrift.Multiplexer and build per-service clients via mp.createClient('ServiceName', ServiceModule, connection). Use it to reduce ports and simplify firewall/load balancer configuration. Note: multiplexed clients and non-multiplexed servers are not wire-compatible.How do HTTP/HTTPS Thrift servers differ from TCP servers in Node.js?
Use thrift.createWebServer(options) to serve over HTTP(S). Services are commonly exposed via routes (for example, /hello, /quote), which is convenient for browser clients. While multiplexing can also be used, routes are typically preferred on the web. HTTP integrates easily with TLS and intermediaries but adds overhead compared with raw TCP; choose based on deployment and performance needs.How do Thrift IDL types map to Node.js, and what should I watch for?
- struct and union become generated constructor-based classes- enum becomes integers (with helper maps); fast and compact
- list and set map to JavaScript arrays (ensure uniqueness yourself for sets)
- map maps to JavaScript objects (key-value hash)
- optional fields may be omitted on the wire; check presence before use
- Exceptions are generated types that can be thrown by the server only if declared in the IDL
Programmer’s Guide to Apache Thrift ebook for free