Skip to content

Commit 8b48e49

Browse files
slinkydeveloperigalshilman
authored andcommitted
Introduce new endpoint() API
1 parent dde607a commit 8b48e49

File tree

7 files changed

+338
-151
lines changed

7 files changed

+338
-151
lines changed

src/endpoint.ts

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
3+
*
4+
* This file is part of the Restate SDK for Node.js/TypeScript,
5+
* which is released under the MIT license.
6+
*
7+
* You can find a copy of the license in file LICENSE in the root
8+
* directory of this repository or package, or at
9+
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
10+
*/
11+
12+
import { KeyedRouter, UnKeyedRouter } from "./types/router";
13+
import { ProtoMetadata } from "./types/grpc";
14+
import { Http2ServerRequest, Http2ServerResponse } from "http2";
15+
import { EndpointImpl } from "./endpoint/endpoint_impl";
16+
17+
/**
18+
* Create a new {@link RestateEndpoint}.
19+
*/
20+
export function endpoint(): RestateEndpoint {
21+
return new EndpointImpl();
22+
}
23+
24+
/**
25+
* The properties describing a gRPC service. Consisting of the name, the object holding the
26+
* implementation, and the descriptor (metadata) describing the service and types.
27+
*/
28+
export interface ServiceOpts {
29+
descriptor: ProtoMetadata;
30+
service: string;
31+
instance: unknown;
32+
}
33+
34+
/**
35+
* Utility interface for a bundle of one or more services belonging together
36+
* and being registered together.
37+
*/
38+
export interface ServiceBundle {
39+
/**
40+
* Called to register the services at the endpoint.
41+
*/
42+
registerServices(endpoint: RestateEndpoint): void;
43+
}
44+
45+
/**
46+
* RestateEndpoint encapsulates all the Restate services served by this endpoint.
47+
*
48+
* A RestateEndpoint can either be served either as HTTP2 server, using the methods {@link listen} or {@link http2Handler},
49+
* or as Lambda, using the method {@link lambdaHandler}.
50+
*
51+
* @example
52+
* A typical endpoint served as HTTP server would look like this:
53+
* ```
54+
* import * as restate from "@restatedev/restate-sdk";
55+
*
56+
* restate
57+
* .endpoint()
58+
* .bindService({
59+
* service: "MyService",
60+
* instance: new myService.MyServiceImpl(),
61+
* descriptor: myService.protoMetadata,
62+
* })
63+
* .listen(8000);
64+
* ```
65+
* @example
66+
* A typical endpoint served as AWS Lambda would look like this:
67+
* ```
68+
* import * as restate from "@restatedev/restate-sdk";
69+
*
70+
* export const handler = restate
71+
* .endpoint()
72+
* .bindService({
73+
* service: "MyService",
74+
* instance: new myService.MyServiceImpl(),
75+
* descriptor: myService.protoMetadata,
76+
* })
77+
* .lambdaHandler();
78+
* ```
79+
*/
80+
export interface RestateEndpoint {
81+
/**
82+
* Adds a gRPC service to be served from this endpoint.
83+
*
84+
* The {@link ServiceOpts} passed here need to describe the following properties:
85+
*
86+
* - The 'service' name: the name of the gRPC service (as in the service definition proto file).
87+
* - The service 'instance': the implementation of the service logic (must implement the generated
88+
* gRPC service interface).
89+
* - The gRPC/protobuf 'descriptor': The protoMetadata descriptor that describes the service, methods,
90+
* and parameter types. It is usually found as the value 'protoMetadata' in the generated
91+
* file '(service-name).ts'
92+
*
93+
* The descriptor is generated by the protobuf compiler and needed by Restate to reflectively discover
94+
* the service details, understand payload serialization, perform HTTP/JSON-to-gRPC transcoding, or
95+
* to proxy the service.
96+
*
97+
* If you define multiple services in the same '.proto' file, you may have only one descriptor that
98+
* describes all services together. You can pass the same descriptor to multiple calls of '.bindService()'.
99+
*
100+
* If you don't find the gRPC/protobuf descriptor, make your you generated the gRPC/ProtoBuf code with
101+
* the option to generate the descriptor. For example, using the 'ts-proto' plugin, make sure you pass
102+
* the 'outputSchema=true' option. If you are using Restate's project templates, this should all be
103+
* pre-configured for you.
104+
*
105+
* @example
106+
* ```
107+
* endpoint.bindService({
108+
* service: "MyService",
109+
* instance: new myService.MyServiceImpl(),
110+
* descriptor: myService.protoMetadata
111+
* })
112+
* ```
113+
*
114+
* @param serviceOpts The options describing the service to be bound. See above for a detailed description.
115+
* @returns An instance of this LambdaRestateServer
116+
*/
117+
bindService(serviceOpts: ServiceOpts): RestateEndpoint;
118+
119+
/**
120+
* Binds a new durable RPC service to the given path. This method is for regular (stateless)
121+
* durably executed RPC services.
122+
*
123+
* The service will expose all properties of the router that are functions as follows:
124+
* If the path is 'acme.myservice' and the router has '{ foo, bar }' as properties, the
125+
* Restate will expose the RPC paths '/acme.myservice/foo' and '/acme.myservice/bar'.
126+
*/
127+
bindRouter<M>(path: string, router: UnKeyedRouter<M>): RestateEndpoint;
128+
129+
/**
130+
* Binds a new stateful keyed durable RPC service to the given path.
131+
* This method is services where each invocation is bound to a key and that may maintain
132+
* state per key.
133+
*
134+
* The service will expose all properties of the router that are functions as follows:
135+
* If the path is 'acme.myservice' and the router has '{ foo, bar }' as properties, the
136+
* Restate will expose the RPC paths '/acme.myservice/foo' and '/acme.myservice/bar'.
137+
*/
138+
bindKeyedRouter<M>(path: string, router: KeyedRouter<M>): RestateEndpoint;
139+
140+
/**
141+
* Adds one or more services to this endpoint. This will call the
142+
* {@link ServiceBundle.registerServices} function to register all services at this endpoint.
143+
*/
144+
bind(services: ServiceBundle): RestateEndpoint;
145+
146+
/**
147+
* Creates the invocation handler function to be called by AWS Lambda.
148+
*
149+
* The returned type of this function is `(event: APIGatewayProxyEvent | APIGatewayProxyEventV2) => Promise<APIGatewayProxyResult | APIGatewayProxyResultV2>`.
150+
* We use `any` types here to avoid a dependency on the `@types/aws-lambda` dependency for consumers of this API.
151+
*
152+
* @returns The invocation handler function for to be called by AWS Lambda.
153+
*/
154+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
155+
lambdaHandler(): (event: any) => Promise<any>;
156+
157+
/**
158+
* Serve this Restate Endpoint as HTTP2 server, listening to the given port.
159+
*
160+
* If the port is undefined, this method will use the port set in the `PORT`
161+
* environment variable. If that variable is undefined as well, the method will
162+
* default to port 9080.
163+
*
164+
* This method's result promise never completes.
165+
*
166+
* This method is a shorthand for:
167+
*
168+
* @example
169+
* ```
170+
* const httpServer = http2.createServer(endpoint.http2Handler());
171+
* httpServer.listen(port);
172+
* ```
173+
*
174+
* If you need to manually control the server lifecycle, we suggest to manually instantiate the http2 server and use {@link http2Handler}.
175+
*
176+
* @param port The port to listen at. May be undefined (see above).
177+
*/
178+
listen(port?: number): Promise<void>;
179+
180+
/**
181+
* Returns an http2 server handler. See {@link listen} for more details.
182+
*/
183+
http2Handler(): (
184+
request: Http2ServerRequest,
185+
response: Http2ServerResponse
186+
) => void;
187+
}

0 commit comments

Comments
 (0)