The RPC Module
Describe service interactions using effects, call your server from the browser and forget that API even exists.
Installation
yarn add express @matechs/express @matechs/rpc @matechs/http-client
yarn add -D @types/express
// one http implementation like
yarn add @matechs/http-client-libcurlModule
import { effect as T } from "@matechs/effect";
import { FunctionN } from "fp-ts/lib/function";
import * as H from "@matechs/http-client";
import * as E from "@matechs/express";
import { array } from "fp-ts/lib/Array";
import { right } from "fp-ts/lib/Either";
import { Exit } from "@matechs/effect/lib/original/exit";
import { Do } from "fp-ts-contrib/lib/Do";
import { isSome } from "fp-ts/lib/Option";
// environment entries
const clientConfigEnv: unique symbol = Symbol();
const serverConfigEnv: unique symbol = Symbol();
// describe an environment that supports RPC
export type Remote<T> = Record<
keyof T,
Record<string, FunctionN<any, T.Effect<any, any, any>>>
>;
// describe a client configuration
interface ClientConfig<M, K extends keyof M> {
[k in K]: {
baseUrl: string;
};
};
}
// create a client configuration
export function clientConfig<M, K extends keyof M>(
_m: M,
k: K
): (c: ClientConfig<M, K>[typeof clientConfigEnv][K]) => ClientConfig<M, K>
// describe a server configuration
interface ServerConfig<M, K extends keyof M> {
[k in K]: {
scope: string;
};
};
}
// create a server configuration
export function serverConfig<M, K extends keyof M>(
_m: M,
k: K
): (c: ServerConfig<M, K>[typeof serverConfigEnv][K]) => ServerConfig<M, K>
// create a client for module M and entry K
export function client<M extends Remote<M>, K extends keyof M>(m: M, k: K): Client<M, K>
// merge environment requirements for the whole module
export type Runtime<M> = M extends {
[h: string]: (...args: any[]) => T.Effect<infer Q & E.RequestContext, any, any>;
}
? Q
: never;
// request object
interface RPCRequest {
args: unknown[];
}
// response object
interface RPCResponse {
value: Exit<unknown, unknown>;
}
// bind module M and entry K to express
export function bind<M extends Remote<M>, K extends keyof M>(
m: M,
k: K
): T.Effect<
E.ExpressEnv & Runtime<M[K]> & ServerConfig<M, K> & M,
T.NoErr,
void
>Usage
Notes
You can wire as many modules as you need! Keep in mind both arguments and return types (error/success) must be serializable in order for RPC to do its magic.
Full example with complete separation of server/client and authentication available at https://github.com/mikearnaldi/matechs-effect/tree/master/packages/rpc/demo.
Last updated
Was this helpful?