fsf
Version:
A typesafe websocket RPC library which thins the borders between clients and servers.
134 lines (86 loc) • 4.35 kB
Markdown
# Functions Without Borders - Fonctions sans Frontières (fsf)
A typesafe websocket RPC library which thins the borders between clients and servers.

While defining a server's APIs using TS, you can automatically define the frontend's function contracts. These functions can be called "natively", as if they're already present in the frontend itself.
## Usage
### Installation
Install the package
```sh
npm i fsf
```
### Common
Define an interface for your api which is accessable in your client and server source code (e.g. by using yarn workspaces).
```ts
export type API = {
hello: () => string;
world: () => string;
sum: (x: number, y: number) => number;
};
```
### Client
> Note: On the client side, all functions return a Promise with the result by default, because of the asynchronous nature of sockets. So, all passed functions are also modified to return a Promise.
```ts
import { Client } from "fsf";
import { API } from "../api";
const client = Client<API>("http://localhost:8080");
const { listFiles, searchMovie } = client;
const main = async () => {
console.log(await client.hello());
// passing multiple parameters to the function
console.log(await client.sum(12, 20));
console.log(await listFiles());
// passing a string parameter
console.log(await searchMovie("kong"));
};
main();
```
### Server
```ts
import { Server } from "fsf";
import { API } from "../api";
import listFiles from "./apis/listFiles";
import searchMovie from "./apis/searchMovie";
const api: API = {
hello: () => "Hello World!",
sum: (x, y) => x + y,
// Make an API call to movies API
searchMovie: searchMovie,
// Fetch all files on server
listFiles: listFiles,
errorFunction: (a: any) => a.b,
};
Server(8080, api);
```
## Error Handling
At the moment, any error on the server-side is sent to `std:error` and thrown on the client side.
Try running `/example/client/throwsError.ts` to check it out.
## What's Not Supported?
1. Passing functions as a parameter. This would require stringifying the function on the frontend and running `eval` on it on the backend, which is an UNSAFE OPERATION.
## How does it work internally?
In short, the library depends on Websockets, Object Proxies, and Typescript generics to work. In detail:
### 1. Websockets
We use socket.io for fast and reliable socket connections. Websockets can be lighter than HTTP requests when a large number of connections are needed. Also, they have a smaller code footprint than HTTP requests. Their usage is anyways abstracted away in the codebase, and they can be replaced with any other technology if needed.
### 2. Object Proxies
The framework utilizes Object Proxies get control over the client object. Any function call made on a property of the client object (or on a deconstructed property), like
```ts
client.functionOne();
// or
const { functionOne } = client;
functionOne();
```
is handled by a `get` property which has been set on the Object Proxy [here](https://github.com/akash-joshi/functions-without-borders/blob/45ed7558845b6dbf03fc368b96ca175262956051/src/client/index.ts#L33).
You can go through the code to see how it uses the property name and parameters to make a socket call to the server.
### 3. Typescript Generics
All of the auto-complete goodness that the framework provides throughout the app depends on Typescript generics. On the server side, the type is directly applied on the API object,
```ts
const api: API = { ...yourApi };
```
while on the client side it's passed to the `Client` initializer.
```ts
const client = Client<API>(endpoint);
```
The client function is actually a generic, which accepts the type provided by the user and applies `Promise` to the return type of each of them. It's a very Typescript-specific piece of code but you can read it [here](https://github.com/akash-joshi/functions-without-borders/blob/01553873cd1a1f1acc66270c5521a74b58680be0/src/client/index.ts#L3).
## Contributing
Pull requests are welcome. You'll probably find lots of improvements to be made.
Open issues for feedback, requesting features, reporting bugs or discussing ideas.
Special thanks to [](https://github.com/mkrhere) for hand-holding me through most of the code.