Send Search Requests
Update src/domain/gateway/book_manager.ts:
@@ -2,4 +2,5 @@ import { Book } from "../model";
export interface BookManager {
indexBook(b: Book): Promise<string>;
+ searchBooks(q: string): Promise<Book[]>;
}
Update src/infrastructure/search/es.ts:
@@ -21,4 +21,17 @@ export class ElasticSearchEngine implements BookManager {
});
return result._id;
}
+
+ async searchBooks(q: string): Promise<Book[]> {
+ const result = await this.client.search({
+ index: INDEX_BOOK,
+ query: {
+ multi_match: {
+ query: q,
+ fields: ["title", "author", "content"],
+ },
+ },
+ });
+ return result.hits.hits.map((hit) => hit._source as Book);
+ }
}
Here we use multi_match
to query on mutilple fields: “title“, “author“ and “content“.
Update src/application/executor/book_operator.ts:
@@ -11,4 +11,8 @@ export class BookOperator {
async createBook(b: Book): Promise<string> {
return await this.bookManager.indexBook(b);
}
+
+ async searchBooks(q: string): Promise<Book[]> {
+ return await this.bookManager.searchBooks(q);
+ }
}
Update src/adapter/router.ts:
@@ -21,6 +21,18 @@ class RestHandler {
res.status(404).json({ error: "Failed to create" });
}
}
+
+ public async searchBooks(req: Request, res: Response): Promise<void> {
+ try {
+ const books = await this.bookOperator.searchBooks(
+ (req.query.q as string) || ""
+ );
+ res.status(201).json(books);
+ } catch (err) {
+ console.error(`Failed to search books: ${err}`);
+ res.status(404).json({ error: "Failed to search" });
+ }
+ }
}
// Create router
@@ -34,6 +46,7 @@ function MakeRouter(wireHelper: WireHelper): express.Router {
res.json({ status: "ok" });
});
router.post("/books", restHandler.createBook.bind(restHandler));
+ router.get("/books", restHandler.searchBooks.bind(restHandler));
return router;
}
Run the server again and try it with curl
:
curl 'http://localhost:3000/books?q=katniss+hunger'
Example response:
[
{
"title": "The Hunger Games",
"author": "Suzanne Collins",
"published_at": "2008-09-14",
"content": "In a dystopian future, teenagers are forced to participate in a televised death match called the Hunger Games. Katniss Everdeen volunteers to take her sister‘s place and becomes a symbol of rebellion."
}
]
Try it in tools like Postman or Insomnia:
http://localhost:3000/books?q=new%20york%20circus%20girl
In URL encoding, both
%20
and+
are used for representing spaces, but they serve slightly different purposes depending on the context.
Great! You just completed a full-text search.
Note:
Full text search requires language analyzers. The default analyzer is the standard analyzer, which may not be the best especially for Chinese, Japanese, or Korean text. With language specific analyzers, you can get better search experience.