Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | import { Api, Endpoint, SimpleMeta, Duplex, ApiTypeOf } from "estuary-rpc";
import { ApiContext, RestEndpoints, ServerOpts, WsEndpoints } from "./types";
import { methodId } from "./middleware";
import { createRestServer, restEndpoint } from "./rest";
import { createWsServer, wsEndpoint } from "./ws";
function flattenApi<T extends Api<unknown, Meta>, Meta extends SimpleMeta>(
api: ApiTypeOf<ApiContext, unknown, T>,
apiMeta: ApiTypeOf<unknown, Meta, T>,
serverOpts: ServerOpts<Meta>
): [RestEndpoints, WsEndpoints] {
const restEndpoints: RestEndpoints = {};
const wsEndpoints: WsEndpoints = {};
Object.keys(apiMeta).forEach((apiName: string) => {
if (typeof apiMeta[apiName] === "function") {
const meta = apiMeta[apiName] as Meta;
if (meta.method === "WS") {
wsEndpoints[methodId(meta)] = wsEndpoint(
api[apiName] as Endpoint<
Duplex<unknown, unknown>,
void,
ApiContext,
unknown
>,
meta,
serverOpts
);
} else {
restEndpoints[methodId(meta)] = restEndpoint(
api[apiName] as Endpoint<unknown, unknown, ApiContext, unknown>,
meta,
serverOpts
);
}
} else {
const [childRest, childWs] = flattenApi(
api[apiName] as any,
apiMeta[apiName] as any,
serverOpts
);
Object.assign(restEndpoints, childRest);
Object.assign(wsEndpoints, childWs);
}
});
return [restEndpoints, wsEndpoints];
}
/**
* createApiServer is the primary method through which your server code will interact with estuary-rpc.
* Calling it will set up and start an 'http' server that listens for HTTP and WS connections and appropriately
* forwards data to your endpoint implementations, taking into account underlying transport encodeings,
* authentication tokens, and the wonkiness of dealing with WebSockets
* @param api Your API definition, the collection of all the endpoint implementations
* @param description Your API Metadata definition, defined in common code with your client
* @param serverOpts options for configuring the server
* * @example
* ```ts
* // Common Code
* export interface ExampleApi<Closure, Meta> extends Api<Closure, Meta> {
* foo: FooService<Closure, Meta>;
* fileUpload: Endpoint<void, void, Closure, Meta>;
* }
*
* export interface FooService<Closure, Meta> extends Api<Closure, Meta> {
* emptyPost: Endpoint<void, void, Closure, Meta>;
* simpleGet: Endpoint<number, number, Closure, Meta>;
* simpleStream: StreamDesc<string, boolean, Closure, Meta>;
* }
*
* export const exampleApiMeta: ExampleApi<never, ExampleMeta> = {
* foo: {
* emptyPost: post("foo/emptyPost"),
* simpleGet: get("foo/simpleGet", { authentication: "bearer", token: "" }),
* simpleStream: ws("foo/simpleStream"),
* },
* fileUpload: post("fileUpload", { uploads: ["someFile.txt"] }),
* };
*
* // Server Code
* const server: ExampleApi<ApiContext, unknown> = {
* foo: {
* emptyPost: async () => {
* console.log("got post");
* },
* simpleGet: async (num: number) => 4,
* simpleStream: async ({ server }: Duplex<string, boolean>) => {
* server.on("message", (input: string) => {
* console.log("Got message", input);
* server.write(input === "foo");
* });
* },
* } as FooService<ApiContext, unknown>,
*
* fileUpload: (_1: void, _2: ApiContext) => {
* return null;
* },
* };
* ```
* @group Server
*/
export function createApiServer<
Meta extends SimpleMeta,
T extends Api<unknown, Meta>
>(
api: ApiTypeOf<ApiContext, unknown, T>,
apiMeta: ApiTypeOf<unknown, Meta, T>,
serverOpts: ServerOpts<Meta>
) {
const [restEndpoints, wsEndpoints] = flattenApi(api, apiMeta, serverOpts);
const server = createRestServer(restEndpoints, serverOpts);
createWsServer(server, wsEndpoints, serverOpts);
server.listen(serverOpts.port);
console.log("Listening on :", serverOpts.port);
}
export * from "estuary-rpc";
export * from "./errors";
export * from "./middleware";
export * from "./multipart";
export * from "./rest";
export * from "./types";
export * from "./ws";
|