Integrating Moleculer Microservices with Deno Deploy at the Edge
In modern web development, combining the strengths of different platforms can lead to highly efficient and scalable architectures. This post demonstrates how to integrate a Moleculer-based microservice application, running on Node.js, with a Deno Deploy edge function, all powered by TypeScript.
Why Moleculer and Deno Deploy?
Moleculer is a fast, scalable, and powerful microservices framework for Node.js. It simplifies building distributed systems with features like service discovery, load balancing, and fault tolerance, making it ideal for complex backend logic. (Moleculer Documentation)
Deno Deploy is a distributed system that allows you to run JavaScript, TypeScript, and WebAssembly at the edge, close to your users. It offers unparalleled speed and simplicity for deploying serverless functions and web applications without managing infrastructure. (Deno Deploy Documentation)
By combining them, Moleculer handles the intricate backend business logic and inter-service communication, while Deno Deploy acts as a lightweight, globally distributed frontend or API gateway, interacting with the Moleculer services.
1. Setting Up the Moleculer Microservice (Node.js)
First, let's create a simple Moleculer project. We'll define a greeter service and an API Gateway service (moleculer-web) to expose it via HTTP. Ensure you have Node.js and npm/yarn installed.
// src/services/greeter.service.ts
import { Service, ServiceBroker } from "moleculer";
export default class GreeterService extends Service {
public constructor(broker: ServiceBroker) {
super(broker);
this.parseServiceSchema({
name: "greeter",
actions: {
hello: {
rest: "GET /hello",
handler: async () => "Hello Moleculer!",
},
welcome: {
rest: "GET /welcome",
params: {
name: "string",
},
handler: async (ctx) => `Welcome, ${ctx.params.name}!`,
},
},
});
}
}
// src/services/api.service.ts
import { Service, ServiceBroker } from "moleculer";
import ApiGateway from "moleculer-web";
export default class ApiService extends Service {
public constructor(broker: ServiceBroker) {
super(broker);
this.parseServiceSchema({
name: "api",
mixins: [ApiGateway],
settings: {
port: process.env.PORT || 3000,
routes: [
{
path: "/api",
whitelist: [
"greeter.*", // Expose all actions of the 'greeter' service
],
},
],
},
});
}
}
// src/broker.ts
import { ServiceBroker } from "moleculer";
import GreeterService from "./services/greeter.service";
import ApiService from "./services/api.service";
const broker = new ServiceBroker({
nodeID: "moleculer-node",
transporter: "NATS", // Or Redis, TCP, etc. for production
logLevel: "info",
});
broker.createService(GreeterService);
broker.createService(ApiService);
export default broker;
To run this Moleculer application, install dependencies (npm i moleculer moleculer-web nats typescript ts-node @types/node) and then execute ts-node src/broker.ts.
2. Deploying a Deno Edge Function
Now, let's create a Deno Deploy application that interacts with our Moleculer API Gateway. This Deno application will be deployed to the edge, providing a low-latency entry point for users. For this example, assume your Moleculer API Gateway is publicly accessible at https://your-moleculer-api.example.com.
// deno-client/main.ts
import { serve } from "https://deno.land/std@0.218.2/http/server.ts";
const MOLECULER_API_URL = Deno.env.get("MOLECULER_API_URL") || "http://localhost:3000";
async function handler(req: Request): Promise<Response> {
const url = new URL(req.url);
const pathname = url.pathname;
if (pathname === "/deno-hello") {
try {
const moleculerResponse = await fetch(`${MOLECULER_API_URL}/api/hello`);
const text = await moleculerResponse.text();
return new Response(`Deno says: ${text}`, { status: 200 });
} catch (error) {
console.error("Error fetching from Moleculer:", error);
return new Response("Failed to connect to Moleculer service", { status: 500 });
}
} else if (pathname === "/deno-welcome") {
const name = url.searchParams.get("name") || "Guest";
try {
const moleculerResponse = await fetch(`${MOLECULER_API_URL}/api/welcome?name=${name}`);
const text = await moleculerResponse.text();
return new Response(`Deno says: ${text}`, { status: 200 });
} catch (error) {
console.error("Error fetching from Moleculer:", error);
return new Response("Failed to connect to Moleculer service", { status: 500 });
}
} else {
return new Response("Not Found", { status: 404 });
}
}
serve(handler);
To deploy this Deno application:
- Save the code as
main.tsin adeno-clientdirectory. - Commit it to a Git repository (e.g., GitHub).
- Go to Deno Deploy and create a new project, linking it to your repository.
- Configure the
MOLECULER_API_URLenvironment variable on Deno Deploy to point to your live Moleculer API Gateway (e.g.,https://your-moleculer-api.example.com).
Once deployed, accessing https://your-deno-app.deno.dev/deno-hello will trigger the Deno function, which in turn calls your Moleculer microservice, demonstrating seamless integration.
Conclusion
By leveraging Moleculer's robust microservices capabilities for backend logic and Deno Deploy's global edge network for client-facing interactions, you can build powerful, high-performance distributed applications. This architecture allows you to scale your services independently, optimize for latency, and utilize the best tools for each part of your system, all within the modern TypeScript ecosystem.