UNPKG

fsf

Version:

A typesafe websocket RPC library which thins the borders between clients and servers.

134 lines (86 loc) 4.35 kB
# Functions Without Borders - Fonctions sans Frontières (fsf) A typesafe websocket RPC library which thins the borders between clients and servers. ![Frame 2](https://user-images.githubusercontent.com/22196279/119225442-6f446400-bb21-11eb-8e63-ae8e62d6dcc9.png) 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 [@mkrhere](https://github.com/mkrhere) for hand-holding me through most of the code.