jianyi-gronk commented on code in PR #394:
URL: https://github.com/apache/dubbo-js/pull/394#discussion_r1605793782


##########
docs/guide/dubboForNode/GettingStarted.md:
##########
@@ -1 +1,196 @@
-# GettingStarted
+# Getting started
+
+Dubbo-Node is a library for serving Dubbo, gRPC, and gRPC-Web compatible HTTP 
APIs using Node.js. It brings the Dubbo Protocol to Node with full TypeScript 
compatibility and support for all four types of remote procedure calls: unary 
and the three variations of streaming.

Review Comment:
   Dubbo-Node -> Dubbo-js



##########
docs/guide/dubboForNode/GettingStarted.md:
##########
@@ -1 +1,196 @@
-# GettingStarted
+# Getting started
+
+Dubbo-Node is a library for serving Dubbo, gRPC, and gRPC-Web compatible HTTP 
APIs using Node.js. It brings the Dubbo Protocol to Node with full TypeScript 
compatibility and support for all four types of remote procedure calls: unary 
and the three variations of streaming.
+
+This ten-minute walkthrough helps you create a small Dubbo service in Node.js. 
It demonstrates what you'll be writing by hand, what Connect generates for you, 
and how to call your new API.
+
+
+# Prerequisites
+We'll set up a project from scratch and then augment it to serve a new 
endpoint.
+
+- You'll need [Node.js](https://nodejs.org/en/download) installed - we 
recommend the most recent long-term support version (LTS).
+- We'll use the package manager `npm`, but we are also compatible with `yarn` 
and `pnpm`.
+- We'll also use [cURL](https://curl.se/). It's available from Homebrew and 
most Linux package managers.
+
+
+# Project setup
+
+Let's initialize a project with TypeScript, and install some code generation 
tools:
+
+```shell
+mkdir dubbo-example
+cd dubbo-example
+npm init -y
+npm install typescript tsx
+npx tsc --init
+npm install @bufbuild/protoc-gen-es @bufbuild/protobuf 
@apachedubbo/protoc-gen-apache-dubbo-es @apachedubbo/dubbo
+```
+
+# Define a service
+First, we need to add a Protobuf file that includes our service definition. 
For this tutorial, we are going to construct a unary endpoint for a service 
that is a stripped-down implementation of 
[ELIZA](https://en.wikipedia.org/wiki/ELIZA), the famous natural language 
processing program.
+
+```shell
+mkdir -p proto && touch proto/example.proto
+```
+
+Open up the above file and add the following service definition:
+
+```Protobuf
+syntax = "proto3";
+
+package apache.dubbo.demo.example.v1;
+
+message SayRequest {
+  string sentence = 1;
+}
+
+message SayResponse {
+  string sentence = 1;
+}
+
+service ExampleService {
+  rpc Say(SayRequest) returns (SayResponse) {}
+}
+```
+
+
+# Generate code
+
+Create the gen directory as the target directory for generating file placement:
+```Shell
+mkdir -p gen
+```
+Run the following command to generate a code file in the gen directory:
+
+```Shell
+PATH=$PATH:$(pwd)/node_modules/.bin \
+  protoc -I proto \
+  --es_out gen \
+  --es_opt target=ts \
+  --apache-dubbo-es_out gen \
+  --apache-dubbo-es_opt target=ts \
+  example.proto
+```
+
+After running the command, the following generated files should be visible in 
the target directory:
+
+```Plain Text
+├── gen
+│   ├── example_dubbo.ts
+│   └── example_pb.ts
+├── proto
+│   └── example.proto
+```
+
+Next, we are going to use these files to implement our service.
+
+
+# Implement the service
+
+We defined the `ElizaService` - now it's time to implement it, and register it 
with the `DubboRouter`. First, let's create a file where we can put the 
implementation:
+
+Create a new file `dubbo.ts` with the following contents:
+
+```typescript
+import { DubboRouter } from "@apachedubbo/dubbo";

Review Comment:
   import { DubboRouter } from "@apachedubbo/dubbo"; -> import type { 
DubboRouter } from "@apachedubbo/dubbo";



##########
docs/guide/dubboForNode/ImplementingServices.md:
##########
@@ -1 +1,234 @@
 # ImplementingServices
+
+Dubbo handles HTTP routes and most plumbing for you, but implementing the 
actual business logic is still up to you.
+
+You always register your implementation on the DubboRouter. We recommend to 
create a file dubbo.ts with a registration function in your project:
+
+
+```ts
+import { DubboRouter } from "@apachedubbo/dubbo";

Review Comment:
   import { DubboRouter } from "@apachedubbo/dubbo"; -> import type { 
DubboRouter } from "@apachedubbo/dubbo";



##########
docs/guide/dubboForNode/ImplementingServices.md:
##########
@@ -1 +1,234 @@
 # ImplementingServices
+
+Dubbo handles HTTP routes and most plumbing for you, but implementing the 
actual business logic is still up to you.
+
+You always register your implementation on the DubboRouter. We recommend to 
create a file dubbo.ts with a registration function in your project:
+
+
+```ts
+import { DubboRouter } from "@apachedubbo/dubbo";
+
+export default (router: DubboRouter) => {}
+```
+
+
+# Register a service
+
+Let's say you have defined a simple service in Protobuf:
+
+```
+message SayRequest {
+  string sentence = 1;
+}
+message SayResponse {
+  string sentence = 1;
+}
+service ElizaService {
+  rpc Say(SayRequest) returns (SayResponse) {}
+}
+```
+
+To register this service, call `router.service()`:
+
+```ts
+import { DubboRouter, HandlerContext } from "@apachedubbo/dubbo";
+import { ElizaService } from "./gen/eliza_dubbo";
+import { SayRequest, SayResponse } from "./gen/eliza_pb";
+
+export default (router: DubboRouter) =>
+  router.service(ElizaService, {
+    async say(req: SayRequest, context: HandlerContext) {
+      return new SayResponse({
+        sentence: `You said ${req.sentence}`,
+      });
+    }
+  });
+```
+
+Your method `say()` receives the request message and a context object, and 
returns a response message. It is a plain function!
+
+
+# Plain functions
+
+Your function can return a response message, or a promise for a response 
message, or just an initializer for a response message:
+
+```ts
+function say(req: SayRequest) {
+  return new SayResponse({ sentence: `You said ${req.sentence}` });
+}
+```
+
+```ts
+async function say(req: SayRequest) {
+  return { sentence: `You said ${req.sentence}` };
+}
+```
+
+```ts
+const say = (req: SayRequest) => ({ sentence: `You said ${req.sentence}` });
+```
+
+You can register any of these functions for the ElizaService.
+
+
+# Context
+
+The context argument gives you access to headers and service metadata:
+
+```ts
+import { HandlerContext } from "@apachedubbo/dubbo";
+import { SayRequest } from "./gen/eliza_pb";
+
+function say(req: SayRequest, context: HandlerContext) {
+  ctx.service.typeName; // the protobuf type name "ElizaService"
+  ctx.method.name; // the protobuf rpc name "Say"
+  context.requestHeader.get("Foo");
+  context.responseHeader.set("Foo", "Bar");
+  return new SayResponse({ sentence: `You said ${req.sentence}` });
+}
+```
+
+It can also be used to access arbitrary values that are passed from either 
server plugins or interceptors. Please refer to the docs on 
[interceptors](Interceptors.md) for learn more.
+
+
+# Errors
+
+Instead of returning a response, your method can also raise an error:
+
+```ts
+import { Code, DubboError } from "@apachedubbo/dubbo";
+
+function say() {
+  throw new DubboError("I have no words anymore.", Code.ResourceExhausted);
+}
+```
+
+`Code` is one of Connects [error codes](). Besides the code and a message, 
errors can also contain metadata (a Headers object) and error details.
+
+
+# Error details
+
+Error details are a powerful feature. Any protobuf message can be transmitted 
as an error detail. Let's use `google.rpc.LocalizedMessage` to localize our 
error message:
+
+```shell
+buf generate buf.build/googleapis/googleapis
+```
+
+```ts
+import { Code, DubboError } from "@apachedubbo/dubbo";
+import { ElizaService } from "./gen/eliza_dubbo";
+import { LocalizedMessage } from "./gen/google/rpc/error_details_pb";
+
+function say() {
+  const details = [
+    new LocalizedMessage({
+      locale: "fr-CH",
+      message: "Je n'ai plus de mots.",
+    }),
+    new LocalizedMessage({
+      locale: "ja-JP",
+      message: "もう言葉がありません。",
+    }),
+  ];
+  const metadata = new Headers({
+    "words-left": "none"
+  });
+  throw new DubboError(
+    "I have no words anymore.",
+    Code.ResourceExhausted,
+    metadata,
+    details
+  );
+}
+```
+
+
+# Streaming
+
+Before showing the various handlers for streaming endpoints, we'd like to 
reference the [Streaming]() page from Dubbo-Go as a caveat. Because while Dubbo 
for Node.js does support all three variations of streaming endpoints, there are 
tradeoffs that should be considered before diving in.
+
+Streaming can be a very powerful approach to APIs in the right circumstances, 
but it also requires great care. Remember, with great power comes great 
responsibility.
+
+In **client streaming**, the client sends multiple messages. Once the server 
receives all the messages, it responds with a single message. In Protobuf 
schemas, client streaming methods look like this:
+
+```
+service ElizaService {
+  rpc Vent(stream VentRequest) returns (VentResponse) {}
+}
+```
+
+In TypeScript, client streaming methods receive an asynchronous iterable of 
request messages (you can iterate over them with a for 
[await...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of)
 loop):
+
+```ts
+async function vent(reqs: AsyncIterable<VentRequest>): Promise<VentResponse> {}
+```
+
+In **server streaming**, the client sends a single message, and the server 
responds with multiple messages. In Protobuf schemas, server streaming methods 
look like this:
+
+```
+service ElizaService {
+  rpc Introduce(IntroduceRequest) returns (stream IntroduceResponse) {}
+}
+```
+
+In TypeScript, server streaming methods receive a request message, and return 
an asynchronous iterable of response messages, typically with a [generator 
function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*).
+
+```ts
+async function *introduce(req: IntroduceRequest) {
+  yield { sentence: `Hi ${req.name}, I'm eliza` };
+  yield { sentence: `How are you feeling today?` };
+}
+```
+
+In **bidirectional streaming** (often called bidi), the client and server may 
both send multiple messages. Often, the exchange is structured like a 
conversation: the client sends a message, the server responds, the client sends 
another message, and so on. Keep in mind that this always requires end-to-end 
HTTP/2 support (regardless of RPC protocol)!
+
+
+# Helper Types
+
+Service implementations are type-safe. The `service()` method of the 
`DubboRouter` accepts a `ServiceImpl<T>`, where `T` is a service type. A 
`ServiceImpl` has a method for each RPC, typed as `MethodImp<M>`, where `M` is 
a method info object.
+
+You can use these types to compose your service without registering it right 
away:
+
+```ts
+import type { MethodImpl, ServiceImpl } from "@apachedubbo/dubbo";
+
+export const say: MethodImpl<typeof ElizaService.methods.say> = ...
+
+export const eliza: ServiceImpl<typeof ElizaService> = {
+  // ...
+};
+
+export class Eliza implements ServiceImpl<typeof ElizaService> {
+  async say(req: SayRequest) {
+    return {
+      sentence: `You said ${req.sentence}`,
+    };
+  }
+}
+```
+
+Registering the examples above:
+
+```ts
+import { DubboRouter } from "@apachedubbo/dubbo";

Review Comment:
   import { DubboRouter } from "@apachedubbo/dubbo"; -> import type { 
DubboRouter } from "@apachedubbo/dubbo";



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@dubbo.apache.org
For additional commands, e-mail: notifications-h...@dubbo.apache.org

Reply via email to