热搜服务集成
让我们从书店 web 服务中调用热搜服务来展示热搜词条。
添加配置项,src/web/infrastructure/config/config.ts:
@@ -15,10 +15,15 @@ interface MQConfig {
topic: string;
}
+export interface RemoteServiceConfig {
+ trend_url: string;
+}
+
export interface Config {
app: ApplicationConfig;
db: DBConfig;
mq: MQConfig;
+ remote: RemoteServiceConfig;
}
export function parseConfig(filename: string): Config {
填入配置值,src/web/config.json:
@@ -10,5 +10,8 @@
"mq": {
"brokers": ["localhost:9094"],
"topic": "lr-book-searches"
+ },
+ "remote": {
+ "trend_url": "http://localhost:3001/trends"
}
}
调用热搜服务,src/web/application/executor/book_operator.ts:
@@ -1,5 +1,5 @@
import { BookManager } from "../../domain/gateway";
-import { Book } from "../../../domain/model";
+import { Book, Trend } from "../../../domain/model";
import { MQHelper } from "../../infrastructure/mq";
export class BookOperator {
@@ -25,4 +25,10 @@ export class BookOperator {
}
return books;
}
+
+ async getTrends(trendURL: string): Promise<Trend[]> {
+ const resp = await fetch(trendURL);
+ const trends: Trend[] = await resp.json();
+ return trends;
+ }
}
集成热搜服务的结果,src/web/adapter/router.ts:
@@ -1,15 +1,18 @@
import express, { Request, Response } from "express";
import { engine } from "express-handlebars";
-import { Book } from "../../domain/model";
+import { Book, Trend } from "../../domain/model";
import { BookOperator } from "../application/executor";
import { WireHelper } from "../application";
+import { RemoteServiceConfig } from "../infrastructure/config";
class RestHandler {
private bookOperator: BookOperator;
+ private remote: RemoteServiceConfig;
- constructor(bookOperator: BookOperator) {
+ constructor(bookOperator: BookOperator, r: RemoteServiceConfig) {
this.bookOperator = bookOperator;
+ this.remote = r;
}
public async indexPage(req: Request, res: Response): Promise<void> {
@@ -21,11 +24,19 @@ class RestHandler {
console.warn(`Failed to get books: ${err}`);
books = [];
}
+ let trends: Trend[];
+ try {
+ trends = await this.bookOperator.getTrends(this.remote.trend_url);
+ } catch (err) {
+ console.warn(`Failed to get trends: ${err}`);
+ trends = [];
+ }
// Render the 'index.handlebars' template, passing data to it
res.render("index", {
layout: false,
title: "LiteRank Book Store",
books,
+ trends,
q,
});
}
@@ -61,9 +72,13 @@ class RestHandler {
}
// Create router
-function MakeRouter(wireHelper: WireHelper): express.Router {
+function MakeRouter(
+ remote: RemoteServiceConfig,
+ wireHelper: WireHelper
+): express.Router {
const restHandler = new RestHandler(
- new BookOperator(wireHelper.bookManager(), wireHelper.messageQueueHelper())
+ new BookOperator(wireHelper.bookManager(), wireHelper.messageQueueHelper()),
+ remote
);
const router = express.Router();
@@ -75,6 +90,7 @@ function MakeRouter(wireHelper: WireHelper): express.Router {
export function InitApp(
templates_dir: string,
+ remote: RemoteServiceConfig,
wireHelper: WireHelper
): express.Express {
const app = express();
@@ -88,7 +104,7 @@ export function InitApp(
// Set the directory for template files
app.set("views", templates_dir);
- const r = MakeRouter(wireHelper);
+ const r = MakeRouter(remote, wireHelper);
app.use("", r);
return app;
}
传入配置项,src/web/app.ts:
@@ -6,7 +6,7 @@ const config_filename = "src/web/config.json";
const c = parseConfig(config_filename);
const wireHelper = new WireHelper(c);
-const app = InitApp(c.app.templates_dir, wireHelper);
+const app = InitApp(c.app.templates_dir, c.remote, wireHelper);
app.listen(c.app.port, () => {
console.log(`Running on port ${c.app.port}`);
渲染 trends
,src/web/adapter/templates/index.handlebars:
@@ -41,17 +41,19 @@
<!-- Trends Section -->
<div class="mb-8">
<h2 class="text-2xl font-bold mb-4">Trends</h2>
- <div class="grid grid-cols-3 gap-4">
- <!-- Trend items can be dynamically generated here -->
- <div class="bg-white p-4 rounded-md border-gray-300 shadow">
- Book 1
- </div>
- <div class="bg-white p-4 rounded-md border-gray-300 shadow">
- Book 2
- </div>
- <div class="bg-white p-4 rounded-md border-gray-300 shadow">
- Book 3
+ <div class="grid grid-cols-5 gap-2">
+ {{#each trends}}
+ <div class="bg-white p-4 rounded-md border-gray-300 shadow mt-2">
+ <div>#<b><a href="/?q={{this.query}}">{{this.query}}</a></b></div>
+ {{#each this.books }}
+ <div class="font-serif border-t py-1 mt-1">
+ {{this.title}}
+ <span class="italic text-sm text-gray-500">by</span>
+ <span class="font-mono italic text-sm">{{this.author}}</span>
+ </div>
+ {{/each}}
</div>
+ {{/each}}
</div>
</div>
重启 web 服务和热搜服务,你将在首页看到如下内容。
第一个服务集成成功!🎉!