From 08458c0ee1ff1069e4f2ffb689a381f85dba4b56 Mon Sep 17 00:00:00 2001 From: igalshilman Date: Thu, 14 Sep 2023 20:56:36 +0200 Subject: [PATCH] Support binding gRPC services that are defined as object literals. This commit allows binding gRPC services directly, in the following way: const greeter = { greet: (req) => TestResponse.create({ greeting: `Hello` }) }; --- src/server/base_restate_server.ts | 25 ++++++++++++++------- test/service_bind.test.ts | 37 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 test/service_bind.test.ts diff --git a/src/server/base_restate_server.ts b/src/server/base_restate_server.ts index 7d298af9..3109bc31 100644 --- a/src/server/base_restate_server.ts +++ b/src/server/base_restate_server.ts @@ -221,6 +221,22 @@ export abstract class BaseRestateServer { } } +/* eslint-disable @typescript-eslint/no-explicit-any */ +function indexProperties(instance: any): Map { + const names = new Map(); + while ( + instance !== null && + instance !== undefined && + instance !== Object.prototype + ) { + for (const property of Object.getOwnPropertyNames(instance)) { + names.set(property.toLowerCase(), property); + } + instance = Object.getPrototypeOf(instance); + } + return names; +} + // Given: // * an instance of a class that implements a gRPC TypeScript interface, // as generated by our protoc plugin, this method @@ -263,14 +279,7 @@ export function parseService( // index all the existing properties that `instance` has. // we index them by the lower case represention. - const prototype = Object.getPrototypeOf(instance); - const names = new Map( - Object.getOwnPropertyNames(prototype).map((name) => [ - name.toLowerCase(), - name, - ]) - ); - + const names = indexProperties(instance); for (const serviceDescriptor of meta.fileDescriptor.service) { if (serviceName !== serviceDescriptor.name) { continue; diff --git a/test/service_bind.test.ts b/test/service_bind.test.ts new file mode 100644 index 00000000..6c8b7ead --- /dev/null +++ b/test/service_bind.test.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 - Restate Software, Inc., Restate GmbH + * + * This file is part of the Restate SDK for Node.js/TypeScript, + * which is released under the MIT license. + * + * You can find a copy of the license in file LICENSE in the root + * directory of this repository or package, or at + * https://github.com/restatedev/sdk-typescript/blob/main/LICENSE + */ + +import { + TestGreeter, + TestRequest, + TestResponse, +} from "../src/generated/proto/test"; +import * as restate from "../src/public_api"; +import { describe } from "@jest/globals"; +import { TestDriver } from "./testdriver"; +import { greetRequest, inputMessage, startMessage } from "./protoutils"; + +const greeter: TestGreeter = { + /* eslint-disable @typescript-eslint/no-unused-vars */ + greet: async (req: TestRequest): Promise => { + restate.useContext(this); + return TestResponse.create({ greeting: `Hello` }); + }, +}; + +describe("BindService", () => { + it("should bind object literals", async () => { + await new TestDriver(greeter, [ + startMessage(1), + inputMessage(greetRequest("Pete")), + ]).run(); + }); +});