I made an Express-like framework for IPC communication
Tags: javascript, node, showdev, typescript
Published: 2022-11-08 06:57:47

For the past two months, I've been developing a CLI (Command Line Interface)
Pomodoro timer and Todo application with Node.js. It will also have a TUI (Text
User Interface) to show statistics with various graphs and charts.

The main idea is: It should be able to create countdown timers and when a timer
finishes it'll give an alarm to remind me to take a break from work. Beside
that, it'll keep logs of my work sessions to show various stats.

It has the following architecture:

```
+-----------+  +--------+  +---------+
|DB (Sqlite)|  | Timer  |  | Speaker |
+-----------+  +--------+  +---------+
             \     |      /
              \    |     /
             +-----------+
             |   Server  |
             +-----------+
              |^      |^
              ||      ||
              v|      v|
           +-----+  +-----+
           | CLI |  | TUI |
           +-----+  +-----+
```

The **Server** runs in the **background as a service.** The CLI and the TUI
communicates with the server over the [IPC](https://en.wikipedia.org/wiki/Inter-process_communication) (**TCP** over **Unix domain
socket** or **Windows Named Pipe**) protocol. The server also needs to able to
broadcast data to it's client.

Though, I can just use a raw socket server with `net.createServer` to do this
communication but it gets a little complicated after a while. Just as you
wouldn't use `http.createServer` instead of a framework like **Express**, I
couldn't go further with this approach.

So, I decided to create my own IPC server framework (as a fun challenge) with
two goals in mind:

1. Request handling feature like Express
1. Data broadcasting to multiple clients

Alhamdulillah (praise be to God) after two weeks of work today I have published
the framework on npm. I named it **Express-IPC.**

See it on [GitHub](https://github.com/h-sifat/express-ipc) and [NPM](https://www.npmjs.com/package/express-ipc).

Example usages:

**server.js**

```js
const { Server } = require("express-ipc");

const socketPath = "./pipe";
const server = new Server();

const users = [
  { id: 1, name: "Alex" },
  { id: 2, name: "Alexa" },
];

server.get("/users/:id", ({ req, res }) => {
  const id = Number(req.params.id);
  const user = users.find((user) => user.id === id);

  if (user) res.send(user);
  else res.send({ message: `No user found with id: ${id}` }, { isError: true });
});

server.listen({
  path: socketPath,
  deleteSocketBeforeListening: true,
  callback() {
    console.log(`Server running on socket: ${server.socketPath}`);
  },
});
```

**client.js**

```js
const { Client } = require("express-ipc");
const socketPath = "./pipe";

main();

async function main() {
  const client = new Client({ path: socketPath });

  try {
    const response = await client.get("/users/1");
    console.log(response);
  } catch (ex) {
    console.log(ex);
  }

  client.close();
}
```

The toughest part was the request routing algorithm.


![Flow chart of request routing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cgq32jr6vduj5921qu39.png)

Sorry, it's too big to fit here and **Dev.to** doesn't support **SVG** files. I
tried to embed the flowchart here but it seems like, **Dev.to** neither supports
[Mermaid](https://mermaid-js.github.io/mermaid/) nor can load my GitHub gist
about the flowchart. See the full chart
[here](https://gist.github.com/h-sifat/196c1e372c5521b67b3c2ea860736067).

Alhamdulillah, I was able to solve it after making a flowchart of the algorithm.
Honestly, It was super boring and took almost a day for me to solve.

As the server framework is completed, now it times for me to go back and
integrate it into my Pomodoro application.

I would love to hear your thoughts about this framework. If you have any
suggestion or feedback please let me know in the comment section 💝.

**Credits:** The background image is taken from [Unsplash](https://unsplash.com/photos/M5tzZtFCOfs?utm_source=unsplash&utm_medium=referral&utm_content=creditShareLink)