Service Integration
Let‘s call the Trend Service to show trends from the bookstore Web Service.
Add config items in service/web/infrastructure/config/config.py:
@@ -25,11 +25,17 @@ class ApplicationConfig:
templates_dir: str
+@dataclass
+class RemoteServiceConfig:
+ trend_url: str
+
+
@dataclass
class Config:
app: ApplicationConfig
db: DBConfig
mq: MQConfig
+ remote: RemoteServiceConfig
def parseConfig(filename: str) -> Config:
@@ -38,5 +44,6 @@ def parseConfig(filename: str) -> Config:
return Config(
ApplicationConfig(**data['app']),
DBConfig(**data['db']),
- MQConfig(**data['mq'])
+ MQConfig(**data['mq']),
+ RemoteServiceConfig(**data['remote'])
)
Put in config values in service/web/config.yml:
@@ -12,3 +12,5 @@ mq:
brokers:
- localhost:9094
topic: "lr-book-searches"
+remote:
+ trend_url: "http://localhost:8001/trends"
Call the trend service in service/web/application/executor/book_operator.py:
@@ -2,9 +2,11 @@ from dataclasses import asdict
from datetime import datetime
import json
from typing import Dict, List
+import urllib.request
+
from .. import dto
-from ....domain.model import Book
+from ....domain.model import Book, Trend
from ...domain.gateway import BookManager
from ...infrastructure.mq import MQHelper
@@ -30,6 +32,11 @@ class BookOperator():
self.mq_helper.send_event(query, json_data)
return books
+ def get_trends(self, trend_url: str) -> List[Trend]:
+ with urllib.request.urlopen(trend_url) as response:
+ data = response.read()
+ return json.loads(data.decode('utf-8'))
+
def _convert(b: Book) -> Dict:
d = asdict(b)
Integrate the trend service results in service/web/adapter/router.py:
@@ -7,11 +7,13 @@ from fastapi.templating import Jinja2Templates
from ..application.executor import BookOperator
from ..application import WireHelper, dto
from ...domain.model import Book
+from ..infrastructure.config.config import RemoteServiceConfig
class RestHandler:
- def __init__(self, logger: logging.Logger, book_operator: BookOperator):
+ def __init__(self, logger: logging.Logger, remote: RemoteServiceConfig, book_operator: BookOperator):
self._logger = logger
+ self.remote = remote
self.book_operator = book_operator
def create_book(self, b: dto.Book):
@@ -30,9 +32,10 @@ class RestHandler:
raise HTTPException(status_code=404, detail="Failed to get books")
-def make_router(app: FastAPI, templates_dir: str, wire_helper: WireHelper):
+def make_router(app: FastAPI, templates_dir: str, remote: RemoteServiceConfig, wire_helper: WireHelper):
rest_handler = RestHandler(
logging.getLogger("lr-event"),
+ remote,
BookOperator(wire_helper.book_manager(),
wire_helper.message_queue_helper())
)
@@ -42,11 +45,14 @@ def make_router(app: FastAPI, templates_dir: str, wire_helper: WireHelper):
@app.get("/", response_class=HTMLResponse)
async def index_page(request: Request, q: str = ""):
books = rest_handler.book_operator.get_books(0, q)
+ trends = rest_handler.book_operator.get_trends(
+ rest_handler.remote.trend_url)
return templates.TemplateResponse(
name="index.html", context={
"request": request,
"title": "LiteRank Book Store",
"books": books,
+ "trends": trends,
"q": q,
}
)
Pass in config items in service/web/main.py:
@@ -9,4 +9,4 @@ CONFIG_FILENAME = "service/web/config.yml"
c = parseConfig(CONFIG_FILENAME)
wire_helper = WireHelper.new(c)
app = FastAPI()
-make_router(app, c.app.templates_dir, wire_helper)
+make_router(app, c.app.templates_dir, c.remote, wire_helper)
Render the trends
in service/web/adapter/templates/index.html:
@@ -38,17 +38,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">
+ {% for trend in trends %}
+ <div class="bg-white p-4 rounded-md border-gray-300 shadow mt-2">
+ <div>#<b><a href="/?q={{trend.query}}">{{trend.query}}</a></b></div>
+ {% for book in trend.books %}
+ <div class="font-serif border-t py-1 mt-1">
+ {{book.title}}
+ <span class="italic text-sm text-gray-500">by</span>
+ <span class="font-mono italic text-sm">{{book.author}}</span>
+ </div>
+ {% endfor %}
</div>
+ {% endfor %}
</div>
</div>
Restart your web and trend services, you should see something like this on the index page.
First service is integrated successfully! 🎉!