» Python: Build a REST API with Flask » 2. Development » 2.11 Search

Search

To implement search functionality in a RESTful API, you typically define a route that handles the search query parameters, searches using the prefix or full-text index in the underlying database, and returns the search results.

Search in MySQL

Add keyword parameter into BookManager.get_books in domain/gateway/book_manager.py:

@@ -22,5 +22,5 @@ class BookManager(ABC):
         pass
 
     @abstractmethod
-    def get_books(self, offset: int) -> List[Book]:
+    def get_books(self, offset: int, keyword: str) -> List[Book]:
         pass

Add search functionality in infrastructure/database/mysql.py:

@@ -61,9 +61,15 @@ class MySQLPersistence(BookManager):
             return None
         return Book(**result)
 
-    def get_books(self, offset: int) -> List[Book]:
-        self.cursor.execute('''
-            SELECT * FROM books LIMIT %s, %s
-        ''', (offset, self.page_size))
+    def get_books(self, offset: int, keyword: str) -> List[Book]:
+        query = "SELECT * FROM books"
+        params: List[Any] = []
+        if keyword:
+            query += " WHERE title LIKE %s OR author LIKE %s"
+            params = [f"%{keyword}%", f"%{keyword}%"]
+        query += " LIMIT %s, %s"
+        params.extend([offset, self.page_size])
+
+        self.cursor.execute(query, tuple(params))
         results: List[Any] = self.cursor.fetchall()
         return [Book(**result) for result in results]

Caution:

Don't do LIKE %keyword% in a production database. It's less efficient compared to other search methods, especially when dealing with large datasets. The LIKE %keyword% syntax forces the database to perform a full table scan or index scan, which can be slow, particularly on large tables. It doesn't leverage indexes efficiently, leading to slower query performance.
If your use case allows, consider using a prefix search (e.g., LIKE keyword%). This can leverage indexes more efficiently compared to substring searches, especially if most searches are for prefixes.

Tune application/executor/book_operator.py:

@@ -23,12 +23,16 @@ class BookOperator():
     def get_book(self, id: int) -> Optional[Book]:
         return self.book_manager.get_book(id)
 
-    def get_books(self, offset: int) -> List[Book]:
+    def get_books(self, offset: int, query: str) -> List[Book]:
+        # Search results, don't cache it
+        if query:
+            return self.book_manager.get_books(offset, query)
+        # Normal results
         k = f"{BOOKS_KEY}-{offset}"
         v = self.cache_helper.load(k)
         if v:
             return json.loads(v)
-        books = self.book_manager.get_books(offset)
+        books = self.book_manager.get_books(offset, "")
         self.cache_helper.save(
             k, json.dumps([_convert(b) for b in books]))
         return books

Pass in the query parameter in adapter/router.py:

@@ -15,8 +15,9 @@ class RestHandler:
 
     def get_books(self):
         try:
-            offset = request.args.get("o", type=int) or 0
-            books = self.book_operator.get_books(offset)
+            offset = request.args.get("o", type=int, default=0)
+            query = request.args.get("q", type=str, default="")
+            books = self.book_operator.get_books(offset, query)
             return jsonify(books), 200
         except Exception as e:
             self._logger.error(f"Failed to get books: {e}")

Save the changes and restart the api server.

Try to search books with curl

Search books

curl -X GET "http://localhost:5000/books?q=and"

Result:

[
  {
    "author": "Jane Austen",
    "created_at": "Sat, 02 Mar 2024 05:48:25 GMT",
    "description": "A classic novel exploring the themes of love, reputation, and social class in Georgian England.",
    "id": 7,
    "isbn": "9780486284736",
    "published_at": "1813-01-28",
    "title": "Pride and Prejudice",
    "total_pages": 279,
    "updated_at": "Sat, 02 Mar 2024 05:48:25 GMT"
  },
  {
    "author": "Leo Tolstoy",
    "created_at": "Sat, 02 Mar 2024 05:48:25 GMT",
    "description": "A novel depicting the Napoleonic era in Russia, exploring themes of love, war, and historical determinism.",
    "id": 13,
    "isbn": "9781400079988",
    "published_at": "1869-01-01",
    "title": "War and Peace",
    "total_pages": 1392,
    "updated_at": "Sat, 02 Mar 2024 05:48:25 GMT"
  },
  {
    "author": "Lewis Carroll",
    "created_at": "Sat, 02 Mar 2024 05:48:25 GMT",
    "description": "A children\u2019s novel featuring a young girl named Alice who falls into a fantastical world populated by peculiar creatures.",
    "id": 14,
    "isbn": "9780141439761",
    "published_at": "1865-11-26",
    "title": "Alice\u2019s Adventures in Wonderland",
    "total_pages": 192,
    "updated_at": "Sat, 02 Mar 2024 05:48:25 GMT"
  }
]

Search books with an offset

curl -X GET "http://localhost:5000/books?q=the&o=4"

Result:

[
  {
    "author": "Mark Twain",
    "created_at": "Sat, 02 Mar 2024 05:48:25 GMT",
    "description": "A novel depicting the journey of a young boy and an escaped slave along the Mississippi River.",
    "id": 12,
    "isbn": "9780486280615",
    "published_at": "1884-12-10",
    "title": "The Adventures of Huckleberry Finn",
    "total_pages": 366,
    "updated_at": "Sat, 02 Mar 2024 05:48:25 GMT"
  },
  {
    "author": "Homer",
    "created_at": "Sat, 02 Mar 2024 05:48:25 GMT",
    "description": "An ancient Greek epic poem attributed to Homer, detailing the journey of Odysseus after the Trojan War.",
    "id": 15,
    "isbn": "9780140268867",
    "published_at": "8th Century BC",
    "title": "The Odyssey",
    "total_pages": 541,
    "updated_at": "Sat, 02 Mar 2024 05:48:25 GMT"
  }
]

Search in mongoDB

Add keyword parameter into ReviewManager.get_reviews_of_book in domain/gateway/review_manager.py:

@@ -22,5 +22,5 @@ class ReviewManager(ABC):
         pass
 
     @abstractmethod
-    def get_reviews_of_book(self, book_id: int) -> List[Review]:
+    def get_reviews_of_book(self, book_id: int, keyword: str) -> List[Review]:
         pass

Add search functionality in infrastructure/database/mongo.py:

@@ -33,8 +33,14 @@ class MongoPersistence(ReviewManager):
             return None
         return Review(**_polish(review_data))
 
-    def get_reviews_of_book(self, book_id: int) -> List[Review]:
-        reviews_data = self.coll.find({"book_id": book_id})
+    def get_reviews_of_book(self, book_id: int, keyword: str) -> List[Review]:
+        filter: Dict[str, Any] = {"book_id": book_id}
+        if keyword:
+            filter["$or"] = [
+                {"title": {"$regex": keyword, "$options": "i"}},
+                {"content": {"$regex": keyword, "$options": "i"}}
+            ]
+        reviews_data = self.coll.find(filter)
         return [Review(**_polish(r)) for r in reviews_data]

Caution:

Regular expression queries can't fully utilize indexes. While some operations may still benefit from indexes, the use of regex can be less efficient compared to exact matches or prefix searches. If your collection has a large number of documents and the field being searched is not indexed, it could lead to slower query performance.

Tune application/executor/review_operator.py:

@@ -21,8 +21,8 @@ class ReviewOperator():
     def get_review(self, id: str) -> Optional[Review]:
         return self.review_manager.get_review(id)
 
-    def get_reviews_of_book(self, review_id: int) -> List[Review]:
-        return self.review_manager.get_reviews_of_book(review_id)
+    def get_reviews_of_book(self, book_id: int, query: str) -> List[Review]:
+        return self.review_manager.get_reviews_of_book(book_id, query)
 
     def update_review(self, id: str, r: Review) -> Review:
         r.updated_at = datetime.now()

Pass in the query parameter in adapter/router.py:

@@ -61,7 +61,8 @@ class RestHandler:
 
     def get_reviews_of_book(self, book_id: int):
         try:
-            reviews = self.review_operator.get_reviews_of_book(book_id)
+            query = request.args.get("q", type=str, default="")
+            reviews = self.review_operator.get_reviews_of_book(book_id, query)
             return jsonify(reviews), 200
         except Exception as e:
             self._logger.error(f"Failed to get reviews of book: {e}")

That's all you need to add search functionality into an API server based on mongoDB. Let's try it out.

Try to search book reviews with curl

Ingest some fake reviews first:

curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Alice Johnson", "title": "A Timeless Classic", "content": "The Great Gatsby is a timeless classic that delves deep into the complexities of the human psyche and the pursuit of the American Dream."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Michael Adams", "title": "Brilliantly Written", "content": "Fitzgerald’s prose in The Great Gatsby is simply brilliant. Each sentence is crafted with care, drawing the reader into a world of opulence and tragedy."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Emily Parker", "title": "Mesmerizing", "content": "I was completely mesmerized by The Great Gatsby. Fitzgerald’s ability to create such vivid characters and evoke a sense of longing is unmatched."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Daniel White", "title": "Enthralling Plot", "content": "The plot of The Great Gatsby is enthralling from start to finish. It’s a story of love, loss, and the emptiness of the American Dream."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Sophia Lee", "title": "A Literary Gem", "content": "The Great Gatsby is a literary gem that shines with its insightful commentary on society and human nature. A must-read for all."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Ethan Miller", "title": "Timeless Masterpiece", "content": "The Great Gatsby remains a timeless masterpiece that continues to resonate with readers across generations. Fitzgerald’s prose is as relevant today as it was in the 1920s."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Olivia Wilson", "title": "Immersive Experience", "content": "Reading The Great Gatsby is an immersive experience like no other. Fitzgerald’s vivid descriptions transport you to the roaring twenties, making you feel like you’re part of the story."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Jacob Thompson", "title": "Intriguing Characters", "content": "What sets The Great Gatsby apart are its intriguing characters. Each one is flawed yet fascinating, contributing to the richness of the narrative."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Ava Martinez", "title": "Gripping Narrative", "content": "The Great Gatsby grips you from the first page and doesn’t let go until the very end. It’s a story that lingers in your mind long after you’ve finished reading."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Noah Taylor", "title": "Profound Themes", "content": "Beneath its glitzy surface, The Great Gatsby explores profound themes of love, betrayal, and the corrupting influence of wealth. A true masterpiece."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Isabella Hernandez", "title": "Hauntingly Beautiful", "content": "The Great Gatsby is hauntingly beautiful, painting a picture of an era filled with glamour and excess, yet tinged with sadness and longing."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Lucas Moore", "title": "Compelling Narrative", "content": "Fitzgerald weaves a compelling narrative in The Great Gatsby, drawing readers into the world of Jay Gatsby and Daisy Buchanan with finesse and skill."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Mia Clark", "title": "Unforgettable Characters", "content": "The characters in The Great Gatsby are unforgettable, each with their own desires and flaws that drive the story forward with intensity and emotion."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Elijah Garcia", "title": "Eloquent Prose", "content": "Fitzgerald’s eloquent prose in The Great Gatsby elevates the novel to literary greatness. It’s a book that demands to be savored and appreciated."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Charlotte King", "title": "Riveting Plot", "content": "The plot of The Great Gatsby is riveting, filled with twists and turns that keep you on the edge of your seat until the very end. An absolute page-turner."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "William Brown", "title": "Emotionally Resonant", "content": "The Great Gatsby is emotionally resonant, exploring themes of love and longing in a way that stays with you long after you’ve turned the final page."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Chloe Rodriguez", "title": "Sensory Delight", "content": "Reading The Great Gatsby is a sensory delight, with Fitzgerald’s vivid descriptions bringing the sights, sounds, and smells of the 1920s to life."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "James Lee", "title": "Thought-Provoking", "content": "The Great Gatsby is thought-provoking, challenging readers to reflect on the nature of wealth, ambition, and the pursuit of happiness."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Emma Taylor", "title": "Rich Symbolism", "content": "The Great Gatsby is rich in symbolism, with every detail serving a purpose in conveying deeper themes and messages about society and human nature."}' http://localhost:5000/reviews
curl -X POST -H "Content-Type: application/json" -d '{"book_id": 4, "author": "Ryan Martinez", "title": "A Literary Masterpiece", "content": "The Great Gatsby is undeniably a literary masterpiece, with its lyrical prose and timeless themes making it a must-read for all lovers of literature."}' http://localhost:5000/reviews

Search reviews by its title or content with keyword: masterpiece

curl -X GET "http://localhost:5000/books/4/reviews?q=masterpiece"

Result:

[
  {
    "author": "Ethan Miller",
    "book_id": 4,
    "content": "The Great Gatsby remains a timeless masterpiece that continues to resonate with readers across generations. Fitzgerald\u2019s prose is as relevant today as it was in the 1920s.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f04",
    "title": "Timeless Masterpiece",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  },
  {
    "author": "Noah Taylor",
    "book_id": 4,
    "content": "Beneath its glitzy surface, The Great Gatsby explores profound themes of love, betrayal, and the corrupting influence of wealth. A true masterpiece.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f08",
    "title": "Profound Themes",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  },
  {
    "author": "Ryan Martinez",
    "book_id": 4,
    "content": "The Great Gatsby is undeniably a literary masterpiece, with its lyrical prose and timeless themes making it a must-read for all lovers of literature.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f12",
    "title": "A Literary Masterpiece",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  }
]

Search reviews by its title or content with keyword: Fitzgerald

curl -X GET "http://localhost:5000/books/4/reviews?q=Fitzgerald"

Result:

[
  {
    "author": "Michael Adams",
    "book_id": 4,
    "content": "Fitzgerald\u2019s prose in The Great Gatsby is simply brilliant. Each sentence is crafted with care, drawing the reader into a world of opulence and tragedy.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f00",
    "title": "Brilliantly Written",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  },
  {
    "author": "Emily Parker",
    "book_id": 4,
    "content": "I was completely mesmerized by The Great Gatsby. Fitzgerald\u2019s ability to create such vivid characters and evoke a sense of longing is unmatched.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f01",
    "title": "Mesmerizing",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  },
  {
    "author": "Ethan Miller",
    "book_id": 4,
    "content": "The Great Gatsby remains a timeless masterpiece that continues to resonate with readers across generations. Fitzgerald\u2019s prose is as relevant today as it was in the 1920s.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f04",
    "title": "Timeless Masterpiece",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  },
  {
    "author": "Olivia Wilson",
    "book_id": 4,
    "content": "Reading The Great Gatsby is an immersive experience like no other. Fitzgerald\u2019s vivid descriptions transport you to the roaring twenties, making you feel like you\u2019re part of the story.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f05",
    "title": "Immersive Experience",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  },
  {
    "author": "Lucas Moore",
    "book_id": 4,
    "content": "Fitzgerald weaves a compelling narrative in The Great Gatsby, drawing readers into the world of Jay Gatsby and Daisy Buchanan with finesse and skill.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f0a",
    "title": "Compelling Narrative",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  },
  {
    "author": "Elijah Garcia",
    "book_id": 4,
    "content": "Fitzgerald\u2019s eloquent prose in The Great Gatsby elevates the novel to literary greatness. It\u2019s a book that demands to be savored and appreciated.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f0c",
    "title": "Eloquent Prose",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  },
  {
    "author": "Chloe Rodriguez",
    "book_id": 4,
    "content": "Reading The Great Gatsby is a sensory delight, with Fitzgerald\u2019s vivid descriptions bringing the sights, sounds, and smells of the 1920s to life.",
    "created_at": "Sat, 02 Mar 2024 07:07:05 GMT",
    "id": "65e2d01909ef3f4e2f726f0f",
    "title": "Sensory Delight",
    "updated_at": "Sat, 02 Mar 2024 07:07:05 GMT"
  }
]

Nice! Search functionality with MySQL or mongoDB is done!

If you want advanced full-text search support, consider using Elasticsearch or Solr. These solutions are optimized for text search operations and offer features such as indexing, relevance scoring, and language-specific stemming.

PrevNext