By Jianyi Cai
Based on the Triple protocol defined by Dubbo3, you can easily develop RPC services that are compatible with browsers and gRPC. These services can run on both HTTP/1 and HTTP/2. The Dubbo TypeScript SDK [1] supports defining services in IDL-specific or programming language-specific ways and provides a set of lightweight APIs for publishing or calling these services.
Dubbo-js has released its first alpha version with support for the Dubbo3 protocol in September. This release presents an opportunity to completely transform the architecture and communication mode of frontend and backend microservices. It allows direct access to backend Dubbo and gRPC services in browser pages or web servers.
This example demonstrates how to develop a web application that runs on a browser using dubbo-js. The web page will call a backend service developed by dubbo node.js and generate the page content. This example showcases both IDL-based and IDL-free encoding modes.
First, we'll use Vite to generate our frontend project template, which has been built into all the feature support we'll need later.
npm create vite@latest -- dubbo-web-example --template react-ts
cd dubbo-web-example
npm install
As Protocol Buffer is used, you must first install code generation tools such as @bufbuild/protoc-gen-es
, @bufbuild/protobuf
, @apachedubbo/protoc-gen-apache-dubbo-es
, and @apachedubbo/dubbo
.
npm install @bufbuild/protoc-gen-es @bufbuild/protobuf @apachedubbo/protoc-gen-apache-dubbo-es @apachedubbo/dubbo
Now, use Protocol Buffer (IDL) to define a Dubbo service.
Create the util/proto directory under src and generate a file.
mkdir -p src/util/proto && touch src/util/proto/example.proto
Enter the following content:
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) {}
}
This file declares a service called ExampleService, and defines a Say method for this service along with its request parameters SayRequest and returned value SayResponse.
Create a gen directory as the target directory where the generated files are placed.
mkdir -p src/util/gen
Run the following command to generate code files under the gen directory by using plug-ins such as protoc-gen-es and protoc-gen-apache-dubbo-es:
PATH=$PATH:$(pwd)/node_modules/.bin \
protoc -I src/util/proto \
--es_out src/util/gen \
--es_opt target=ts \
--apache-dubbo-es_out src/util/gen \
--apache-dubbo-es_opt target=ts \
example.proto
After running the command, you should see the following generated files in the target directory:
├── src
│ ├── util
│ │ ├── gen
│ │ │ ├── example_dubbo.ts
│ │ │ └── example_pb.ts
│ │ └── proto
│ │ └── example.proto
You need to download @apachedubbo/dubbo-web
first.
npm install @apachedubbo/dubbo-web
Now you can import the service from the package and set up a client. Add the following content to App.tsx:
import { useState } from "react";
import "./App.css";
import { createPromiseClient } from "@apachedubbo/dubbo";
import { createDubboTransport } from "@apachedubbo/dubbo-web";
// Import service definition that you want to connect to.
import { ExampleService } from "./util/gen/example_dubbo";
// The transport defines what type of endpoint we're hitting.
// In our example we'll be communicating with a Dubbo endpoint.
const transport = createDubboTransport({
baseUrl: "http://localhost:8080",
});
// Here we make the client itself, combining the service
// definition with the transport.
const client = createPromiseClient(ExampleService, transport, { serviceGroup: 'dubbo', serviceVersion: '1.0.0' });
function App() {
const [inputValue, setInputValue] = useState("");
const [messages, setMessages] = useState<
{
fromMe: boolean;
message: string;
}[]
>([]);
return (
<>
<ol>
{messages.map((msg, index) => (
<li key={index}>{`${msg.fromMe ? "ME:" : "Dubbo Server:"} ${msg.message}`}</li>
))}
</ol>
<form
onSubmit={async (e) => {
e.preventDefault();
// Clear inputValue since the user has submitted.
setInputValue("");
// Store the inputValue in the chain of messages and
// mark this message as coming from "me"
setMessages((prev) => [
...prev,
{
fromMe: true,
message: inputValue,
},
]);
const response = await client.say({
sentence: inputValue,
});
setMessages((prev) => [
...prev,
{
fromMe: false,
message: response.sentence,
},
]);
}}
>
<input value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
<button type="submit">Send</button>
</form>
</>
);
}
export default App;
Run the following command to obtain the sample page:
npm run dev
Next, you need to start the Server. You can use any programming language supported by Dubbo, such as Java, Go, and Node.js, to develop the Server. In this example, the Node.js server embedded in the Dubbo service is used. For more information, see Develop Dubbo backend services with Node.js [2].
However, it should be noted that you need to modify the Node.js example: introduce @fastify/cors
to solve the cross-region problem of frontend requests.
npm install @fastify/cors
It needs to be modified in the server.ts file.
...
import cors from "@fastify/cors";
...
async function main() {
const server = fastify();
...
await server.register(cors, {
origin: true,
});
...
await server.listen({ host: "localhost", port: 8080 });
...
}
void main();
Finally, run the code to start the service.
npx tsx server.ts
In future releases, we will continue to provide support for IDL-free communication, making it easier to access backend services without IDL. Let's take a quick look at how to use the IDL-free mode.
Begin by installing @apachedubbo/dubbo
and @apachedubbo/dubbo-web
.
npm install @apachedubbo/dubbo @apachedubbo/dubbo-web
Now you can start one client at a time and make calls. The code in App.tsx is similar to the IDL-based mode, with a few differences:
// ...
// set backend server to connect
const transport = createDubboTransport({
baseUrl: "http://localhost:8080",
});
// init client
const client = createPromiseClient(transport);
function App() {
// ...
// call remote Dubbo service
const response = await client.call(
"apache.dubbo.demo.example.v1.ExampleService",
"say",
{
sentence: inputValue,
});
}
Run the following command to obtain the sample page:
npm run dev
The upgrade of the Dubbo Triple protocol and the release of the Dubbo JavaScript SDK are powerful additions to the entire microservice system. We anticipate that they will bring significant changes to the architecture of microservices and the communication mode between frontend and backend in the future.
[1] Dubbo TypeScript SDK
https://github.com/apache/dubbo-js/
[2] Develop Dubbo backend service with Node.js
https://github.com/apache/dubbo-js/tree/dubbo3/example/dubbo-node-example
Apache RocketMQ EventBridge: Build the Next Generation of Event-driven Engines
513 posts | 50 followers
FollowAlibaba Cloud Native Community - December 7, 2023
Alibaba Cloud Native Community - September 12, 2023
Alibaba Cloud Native Community - January 26, 2024
Alibaba Cloud Native Community - August 1, 2024
Alibaba Cloud Native Community - December 19, 2023
Alibaba Cloud Native Community - September 12, 2023
513 posts | 50 followers
FollowMSE provides a fully managed registration and configuration center, and gateway and microservices governance capabilities.
Learn MoreAlibaba Cloud Function Compute is a fully-managed event-driven compute service. It allows you to focus on writing and uploading code without the need to manage infrastructure such as servers.
Learn MoreHigh Performance Computing (HPC) and AI technology helps scientific research institutions to perform viral gene sequencing, conduct new drug research and development, and shorten the research and development cycle.
Learn MoreDeploy custom Alibaba Cloud solutions for business-critical scenarios with Quick Start templates.
Learn MoreMore Posts by Alibaba Cloud Native Community