@ananay-nag/universal-client
Version:
Universal multi-server-type client for gRPC, HTTP(S), and Socket.IO services with security middleware support.
213 lines (152 loc) • 6.83 kB
Markdown
# <img src="./universal-client-logo.png" alt="universal-client-logo" style="width:50px;margin-bottom:-15px;"/> Universal-Client
**A TypeScript-first library for seamless, configuration-driven communication with gRPC, HTTP(S), and Socket.IO services—optimized for modern service architectures and high-performance apps.**
<img src="./universal-client.png" alt="universal-client" style="width:60%;min-width:400px; margin-left: 20%"/>
## 🚀 Why universal-client?
Tired of writing separate glue code for HTTP, gRPC, and WebSocket/Socket.IO? Want a **single, typed, persistent, and zero-boilerplate way** to invoke any service from any node in your network (client, server, microservice, event handler, etc.)?
**universal-client** gives you all that—and more!
- **Direct and unified API:** No need to spin up a separate proxy, API gateway, or BFF.
- **Low latency:** Uses pooled, persistent gRPC and Socket.IO connections.
- **TypeScript-first:** Typed interfaces and generic results for backend, frontend, and service-to-service calls.
- **Configurable & Extensible:** Map endpoints to protocols, routes, and remote methods via simple config.
- **All-in-one:** HTTP(S), gRPC, Socket.IO—use any, all, anytime, anywhere.
- **Production-ready:** Focus on business logic, never on protocol friction, reliability, or connection churn.
## ✨ Features
- 🔌 **Multi-Server:** gRPC, HTTP(S), Socket.IO support (add more easily\*)
- 🏎️ **Persistent**: Pools gRPC & Socket clients for speed and resource efficiency.
- 🧩 **Pluggable/Configurable:** All endpoint definitions are in JSON or JS config. Novice-friendly!
- 🛡️ **Strong Typing:** Types/interfaces for all calls, working across browser and backend.
- ⏱️ **Optimized Latency:** Built-in timeouts, connection reuse, minimal setup per call.
- ♾️ **Universal Use:** Works from Node.js, Express, gRPC servers/clients, Socket servers, React/Next.js (web).
- ◀️ **Bi-directional:** Every server can also be a client—microservices nirvana.
- 🚦 **Error Handling:** Standardized, evented, and debuggable.
- 📚 **Easy Extendability:** Add more protocols or custom transports as needed.
## 🔥 How is this different from ordinary API clients or SDKs?
- **No API gateway or full BFF required:** Communicate _directly and programmatically_ with any protocol—no middleware layer, no DSL parsing.
- **Multi-protocol out of the box:** HTTP, gRPC, Socket.IO, all are first-class.
- **Configuration, not code:** Change protocol/server mappings instantly—no redeploy.
- **Strong, static typing:** Share interfaces with backend and frontend—no more `any`s or manual axios calls.
- **Persistent**: gRPC and Socket.IO connections are reused, not reopened every call.
- **Easy to embed**: Use just like any DB driver or HTTP lib, but works with every protocol you care about.
- **Ideal for...** microservices, modern SaaS, DDD, cloud-native, and “polyglot” architectures.
## ⚡️ Example Use Cases
- **React UI making real-time and HTTP calls through a unified method**
- **Express middleware service exchanging data with both gRPC and HTTP services**
- **A gRPC server acting as a client to HTTP and Socket.IO backends**
- **Chat server sending analytics events to REST microservices**
## 📦 Installation
```bash
npm install universal-client
or
yarn add universal-client
```
## 🛠️ Quick Start
### 1. Define your endpoints and protocols
```typescript
import { UniversalClient } from "universal-client";
import { UniversalClientConfig } from "universal-client/dist/types";
const config: UniversalClientConfig = {
endpoints: {
createUser: {
protocol: "grpc",
host: "localhost",
port: 50051,
serviceName: "user.UserService",
methodName: "CreateUser",
protoFile: "./protos/user.proto",
},
sendChat: {
protocol: "socket",
host: "http://localhost",
port: 3001,
event: "sendMessage",
},
signup: {
protocol: "http",
host: "http://localhost:4000",
path: "/api/signup",
methodName: "POST",
},
},
};
```
### 2. Create and use your client anywhere
```typescript
const client = new UniversalClient(config);
// gRPC call
const user = await client.call("createUser", {
username: "alice",
email: "alice@example.com",
});
// Socket.io call
const chatResp = await client.call("sendChat", { message: "hello world" });
// HTTP call
const signupResp = await client.call("signup", {
username: "bob",
password: "supersecure",
});
```
## 🏗️ Examples
### a) In a gRPC server (service-to-service communication):
```RPC
// gRPC handler
async function CreateUser(call, callback) {
// Notify chat via Socket.IO and signup via HTTP/S
await universalClient.call('sendChat', { message: ${call.request.username} signed up! });
await universalClient.call('signup', { ...call.request, password: 'auto-gen' });
// Respond as normal
callback(null, { id: '42', ...call.request });
}
```
### b) In a Socket.IO server:
```typescript
io.on("connection", (socket) => {
socket.on("register", async (payload, cb) => {
const user = await universalClient.call("createUser", payload); // gRPC call
cb({ user });
});
});
```
### c) In an Express API:
```typescript
app.post('/user', async (req, res) => {
const user = await universalClient.call('createUser', req.body); // gRPC
await universalClient.call('sendChat', { message: New user: ${user.username} }); // Socket
res.json(user);
});
```
## 🤖 TypeScript Typings
You can define your own interfaces for request/response types—and use codegen from `.proto` files for *full type safety*.
## ⚙️ Advanced Config
- **Timeouts:**
Pass optional `{ timeoutMs: 5000 }` as the third argument to `.call()` for custom timeouts.
- **Extending protocols:**
PRs welcome! Add NATS, MQTT, Rabbit, or custom protocols by simply dropping in a new client module.
## 💡 Tips & Best Practices
- Share domain model types with backends (using a `@yourorg/protos` npm package).
- Use a config per environment (dev, staging, prod).
- For browser-based gRPC, use `grpc-web`*; for Node, `@grpc/grpc-js` is native.
- Works in Monorepo or Polyrepo architectures.
## 🖥️ API
### UniversalClient
- `constructor(config: UniversalClientConfig)`
- `call<T>(key: string, payload: any, options: UniversalClientCallOptions = {}): Promise<T>`
## 🤩 Ready to Modernize Your Service Calls?
**Stop copying boilerplate and juggling SDKs. Power your microservices, apps, and cross-stack comms the _intelligent_, _clean_, and _typed_ way.**
## 📄 License
MIT
## 🌟 Contributing/Feedback
We welcome PRs and issues! If there's a protocol or feature you'd like, open a discussion on GitHub.