{"id":51607,"date":"2025-05-12T14:04:10","date_gmt":"2025-05-12T14:04:10","guid":{"rendered":"https:\/\/accuweb.cloud\/resource\/?post_type=faq&#038;p=51607"},"modified":"2026-02-17T12:53:41","modified_gmt":"2026-02-17T12:53:41","slug":"build-a-python-flask-crud-app-with-elasticsearch","status":"publish","type":"faq","link":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch","title":{"rendered":"How to Build a Python Flask CRUD App with Elasticsearch?"},"content":{"rendered":"<p>Ever wanted to build your web app that can store data, let you search through it, and even update or delete stuff when needed? Well, that\u2019s exactly what we\u2019re going to do today but with a twist. Instead of using the usual databases, we\u2019re going to use the power of <b>Elasticsearch<\/b>.<\/p>\n<p>First things first, if you haven\u2019t already installed <b>Elasticsearch on your Ubuntu 22.04 VPS<\/b>, no problem. I\u2019ve put together an easy-to-follow guide to get you set up in no time.<\/p>\n<div class=\"main-tooltip-btn\"><a class=\"tooltip-link\" href=\"https:\/\/accuweb.cloud\/resource\/articles\/install-elastic-search-on-ubuntu-22-04\" target=\"_blank\" rel=\"noopener\"><button class=\"tooltip-btn\">Elasticsearch on Ubuntu VPS <i class=\"fa-solid fa-arrow-right-long\"><\/i><br \/>\n<\/button><\/a><\/div>\n<p>Once you have that running, we\u2019ll move on to building a <b>Python Flask CRUD (Create, Read, Update, Delete) API app with Elasticsearch as the backend<\/b>.<\/p>\n<p>Don\u2019t worry if that sounds a bit technical. We\u2019ll walk you through it step by step. Whether you want to create a book database, a basic blog with a built-in search feature, or even a custom search tool for your website, this guide will help you get started from scratch. By the end, you\u2019ll have a working app you can use and test.<\/p>\n<div class=\"article-space\"><\/div>\n<h2 class=\"ack-h2\">Prerequisites and Setup<\/h2>\n<p>Here\u2019s what you need:<\/p>\n<ul class=\"ack-ul\">\n<li>A VPS with Ubuntu 22.04 and Elastic Search running<\/li>\n<li>Basic Python knowledge<\/li>\n<li>Familiarity with HTTP methods: GET, POST, DELETE<\/li>\n<\/ul>\n<div class=\"article-space\"><\/div>\n<h2 class=\"ack-h2\">Installing Python and Flask on Ubuntu VPS<\/h2>\n<p>Run the following commands to install the Python packages:<\/p>\n<pre><code class=\"language-javascript\">sudo apt install python3-pip -y<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/01.png\"><img fetchpriority=\"high\" decoding=\"async\" class=\"aligncenter size-full wp-image-51610\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/01.png\" alt=\"\" width=\"1474\" height=\"347\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/01.png 1474w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/01-300x71.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/01-1024x241.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/01-768x181.png 768w\" sizes=\"(max-width: 1474px) 100vw, 1474px\" \/><\/a><\/p>\n<pre><code class=\"language-javascript\">pip3 install flask elasticsearch<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/02.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-51627\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/02.png\" alt=\"\" width=\"1381\" height=\"243\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/02.png 1381w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/02-300x53.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/02-1024x180.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/02-768x135.png 768w\" sizes=\"(max-width: 1381px) 100vw, 1381px\" \/><\/a><\/p>\n<pre><code class=\"language-javascript\">sudo apt install jq -y<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/18.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-51613\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/18.png\" alt=\"\" width=\"1198\" height=\"512\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/18.png 1198w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/18-300x128.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/18-1024x438.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/18-768x328.png 768w\" sizes=\"(max-width: 1198px) 100vw, 1198px\" \/><\/a><\/p>\n<p>This sets up Flask (a lightweight web framework) and the official Python client for Elastic Search.<\/p>\n<p>Creating Your Flask Application Directory<\/p>\n<pre><code class=\"language-javascript\">mkdir mysearchapp<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<pre><code class=\"language-javascript\">cd mysearchapp<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/03.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51611\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/03.png\" alt=\"\" width=\"1764\" height=\"191\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/03.png 1764w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/03-300x32.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/03-1024x111.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/03-768x83.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/03-1536x166.png 1536w\" sizes=\"(max-width: 1764px) 100vw, 1764px\" \/><\/a><\/p>\n<pre><code class=\"language-javascript\">nano app.py<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/04.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51612\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/04.png\" alt=\"\" width=\"929\" height=\"174\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/04.png 929w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/04-300x56.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/04-768x144.png 768w\" sizes=\"(max-width: 929px) 100vw, 929px\" \/><\/a><\/p>\n<p>In Config,<\/p>\n<p>Go to root -&gt; mysearchapp -&gt; app.py<\/p>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/05.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51614\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/05.png\" alt=\"\" width=\"1779\" height=\"694\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/05.png 1779w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/05-300x117.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/05-1024x399.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/05-768x300.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/05-1536x599.png 1536w\" sizes=\"(max-width: 1779px) 100vw, 1779px\" \/><\/a><\/p>\n<p>Paste the following base structure inside app.py:<\/p>\n<pre><code class=\"language-javascript\">from flask import Flask, request, jsonify\r\nfrom elasticsearch import Elasticsearch\r\n\u00a0\r\napp = Flask(__name__)\r\nes = Elasticsearch(\"http:\/\/localhost:9200\")\r\n\u00a0\r\n@app.route('\/')\r\ndef home();\r\n\u00a0\u00a0\u00a0\u00a0return \"Welcome to the Book Search API!\"<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/06-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51628\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/06-1.png\" alt=\"\" width=\"1771\" height=\"629\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/06-1.png 1771w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/06-1-300x107.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/06-1-1024x364.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/06-1-768x273.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/06-1-1536x546.png 1536w\" sizes=\"(max-width: 1771px) 100vw, 1771px\" \/><\/a><\/p>\n<div class=\"article-space\"><\/div>\n<h2 class=\"ack-h2\">Adding and Searching Books in Elastic Search<\/h2>\n<h3 class=\"ack-h3\">Add Books:<\/h3>\n<pre><code class=\"language-javascript\">@app.route('\/add', methods=['POST'])\r\ndef add_book():\r\n\u00a0\u00a0\u00a0\u00a0data = request.json\r\n\u00a0\u00a0\u00a0\u00a0res = es.index(index=\"books\", document=data)\r\n\u00a0\u00a0\u00a0\u00a0return jsonify(res['result'])<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/07.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51615\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/07.png\" alt=\"\" width=\"1686\" height=\"709\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/07.png 1686w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/07-300x126.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/07-1024x431.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/07-768x323.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/07-1536x646.png 1536w\" sizes=\"(max-width: 1686px) 100vw, 1686px\" \/><\/a><\/p>\n<h3 class=\"ack-h3\">Search Books by Title or Author:<\/h3>\n<pre><code class=\"language-javascript\">@app.route('\/search')\r\ndef search():\r\n\u00a0\u00a0\u00a0\u00a0query = request.args.get('q')\r\n\u00a0\u00a0\u00a0\u00a0res = es.search(index=\"books\", query={\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"multi_match\": {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"query\": query,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"fields\": [\"title\", \"author\"]\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0})\r\n\u00a0\u00a0\u00a0\u00a0books = [doc['_source'] for doc in res['hits']['hits']]\r\n\u00a0\u00a0\u00a0\u00a0return jsonify(books)<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/08.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51616\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/08.png\" alt=\"\" width=\"1588\" height=\"670\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/08.png 1588w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/08-300x127.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/08-1024x432.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/08-768x324.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/08-1536x648.png 1536w\" sizes=\"(max-width: 1588px) 100vw, 1588px\" \/><\/a><\/p>\n<div class=\"article-space\"><\/div>\n<h2 class=\"ack-h2\">View All Books<\/h2>\n<pre><code class=\"language-javascript\">@app.route('\/all')\r\ndef get_all_books():\r\n\u00a0\u00a0\u00a0\u00a0res = es.search(index=\"books\", query={\"match_all\": {}}, size=1000)\r\n\u00a0\u00a0\u00a0\u00a0books = [doc['_source'] for doc in res['hits']['hits']]\r\n\u00a0\u00a0\u00a0\u00a0return jsonify(books)<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/09.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51617\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/09.png\" alt=\"\" width=\"1727\" height=\"682\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/09.png 1727w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/09-300x118.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/09-1024x404.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/09-768x303.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/09-1536x607.png 1536w\" sizes=\"(max-width: 1727px) 100vw, 1727px\" \/><\/a><\/p>\n<div class=\"article-space\"><\/div>\n<h2 class=\"ack-h2\">Updating and Deleting Books<\/h2>\n<h3 class=\"ack-h3\">Update Book<\/h3>\n<pre><code class=\"language-javascript\">@app.route('\/update', methods=['POST'])\r\ndef update_book():\r\n\u00a0\u00a0\u00a0\u00a0data = request.get_json()\r\n\u00a0\u00a0\u00a0\u00a0old_title = data.get('old_title')\r\n\u00a0\u00a0\u00a0\u00a0res = es.search(index=\"books\", query={\"match\": {\"title\": old_title}})\r\n\u00a0\u00a0\u00a0\u00a0if res['hits']['total']['value'] == 0:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": \"Book not found!\"}), 404\r\n\u00a0\r\n\u00a0\u00a0\u00a0\u00a0book_id = res['hits']['hits'][0]['_id']\r\n\u00a0\u00a0\u00a0\u00a0es.update(index=\"books\", id=book_id, body={\"doc\": data})\r\n\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": \"Book updated!\"})<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/10.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51618\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/10.png\" alt=\"\" width=\"1437\" height=\"708\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/10.png 1437w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/10-300x148.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/10-1024x505.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/10-768x378.png 768w\" sizes=\"(max-width: 1437px) 100vw, 1437px\" \/><\/a><\/p>\n<h3 class=\"ack-h3\">Delete Book<\/h3>\n<pre><code class=\"language-javascript\">@app.route('\/delete', methods=['POST'])\r\ndef delete_book():\r\n\u00a0\u00a0\u00a0\u00a0data = request.get_json()\r\n\u00a0\u00a0\u00a0\u00a0title = data.get('title')\r\n\u00a0\u00a0\u00a0\u00a0res = es.search(index=\"books\", query={\"match\": {\"title\": title}})\r\n\u00a0\u00a0\u00a0\u00a0if res['hits']['total']['value'] == 0:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": \"Book not found!\"}), 404\r\n\u00a0\r\n\u00a0\u00a0\u00a0\u00a0book_id = res['hits']['hits'][0]['_id']\r\n\u00a0\u00a0\u00a0\u00a0es.delete(index=\"books\", id=book_id)\r\n\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": \"Book deleted!\"})<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<div class=\"article-space\"><\/div>\n<h2 class=\"ack-h2\">Simple Frontend with HTML + JavaScript<\/h2>\n<p>Create a folder:<\/p>\n<pre><code class=\"language-javascript\">mkdir templates<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/12.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51619\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/12.png\" alt=\"\" width=\"1327\" height=\"205\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/12.png 1327w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/12-300x46.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/12-1024x158.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/12-768x119.png 768w\" sizes=\"(max-width: 1327px) 100vw, 1327px\" \/><\/a><\/p>\n<p>Create file index.html<\/p>\n<pre><code class=\"language-javascript\">nano index.html<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/13.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51620\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/13.png\" alt=\"\" width=\"1184\" height=\"323\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/13.png 1184w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/13-300x82.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/13-1024x279.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/13-768x210.png 768w\" sizes=\"(max-width: 1184px) 100vw, 1184px\" \/><\/a><\/p>\n<p>Inside templates\/index.html:<\/p>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/14.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51621\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/14.png\" alt=\"\" width=\"1576\" height=\"524\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/14.png 1576w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/14-300x100.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/14-1024x340.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/14-768x255.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/14-1536x511.png 1536w\" sizes=\"(max-width: 1576px) 100vw, 1576px\" \/><\/a><\/p>\n\t\t<div data-elementor-type=\"section\" data-elementor-id=\"38668\" class=\"elementor elementor-38668\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\" data-elementor-post-type=\"elementor_library\">\n\t\t\t        <section class=\"elementor-section elementor-top-section elementor-element elementor-element-882321f elementor-section-boxed elementor-section-height-default elementor-section-height-default ct-header-fixed-none ct-row-max-none\" data-id=\"882321f\" data-element_type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n            \n                        <div class=\"elementor-container elementor-column-gap-default \">\n                    <div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7cc79cc\" data-id=\"7cc79cc\" data-element_type=\"column\">\n        <div class=\"elementor-widget-wrap elementor-element-populated\">\n                    \n        \t\t<div class=\"elementor-element elementor-element-e31b40f elementor-widget elementor-widget-shortcode\" data-id=\"e31b40f\" data-element_type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t            <\/div>\n        <\/div>\n                    <\/div>\n        <\/section>\n        \t\t<\/div>\n\t\t\n<div class=\"article-space\"><\/div>\n<p>In index.html:<\/p>\n<pre><code class=\"language-javascript\">&lt;!DOCTYPE html&gt;\r\n&lt;html lang=\"en\"&gt;\r\n&lt;head&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;title&gt;Book Manager&lt;\/title&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;!-- Google Fonts for a modern look --&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;link href=\"https:\/\/fonts.googleapis.com\/css2?family=Montserrat:wght@400;600&amp;display=swap\" rel=\"stylesheet\"&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0&lt;style&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0:root {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0--primary: #6C63FF;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0--primary-light: #a39cff;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0--accent: #F9A826;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0--bg: #f7f7fa;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0--card-bg: #fff;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0--success: #4BB543;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0--error: #FF5252;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0font-family: 'Montserrat', Arial, sans-serif;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0background: var(--bg);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0margin: 0;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0padding: 0;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.container {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0max-width: 800px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0margin: 40px auto;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0padding: 30px 20px 40px 20px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0background: var(--card-bg);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border-radius: 18px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0box-shadow: 0 6px 32px rgba(108,99,255,0.10), 0 1.5px 8px rgba(0,0,0,0.07);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0animation: fadeIn 1s;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0h1 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0text-align: center;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0color: var(--primary);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0font-weight: 700;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0margin-bottom: 24px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0letter-spacing: 1px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0font-size: 2.4rem;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0h3 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0margin-top: 32px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0color: #333;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0font-weight: 600;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0letter-spacing: 0.5px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.form-group {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0display: flex;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0gap: 10px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0margin-bottom: 10px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0flex-wrap: wrap;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0input, button, textarea {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border-radius: 8px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border: none;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0outline: none;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0font-size: 1rem;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0transition: box-shadow 0.2s, border 0.2s;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0input, textarea {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0background: #f2f2f7;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0padding: 10px 12px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border: 1.5px solid #e0e0e0;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0input:focus, textarea:focus {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border-color: var(--primary);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0box-shadow: 0 0 0 2px #6c63ff22;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0button {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0background: var(--primary);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0color: #fff;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0padding: 10px 22px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0font-weight: 600;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0cursor: pointer;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border: none;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0box-shadow: 0 2px 8px #6c63ff22;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0transition: background 0.2s, transform 0.1s;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0button:hover, button:focus {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0background: var(--accent);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0color: #222;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0transform: translateY(-2px) scale(1.04);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0textarea {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0margin-top: 10px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0resize: vertical;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0min-height: 100px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0max-height: 300px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0table {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border-collapse: separate;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border-spacing: 0;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0width: 100%;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0margin-top: 18px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0background: #fff;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border-radius: 12px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0overflow: hidden;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0box-shadow: 0 2px 12px #6c63ff14;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0animation: fadeInUp 0.7s;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0th, td {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0padding: 12px 14px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0text-align: left;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0th {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0background: var(--primary-light);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0color: #fff;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0font-weight: 600;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0tr {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0transition: background 0.2s;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0tr:hover {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0background: #f6f5ff;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0tr.fade-in {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0animation: fadeInRow 0.6s;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/* Toast notification *\/\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.toast {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0position: fixed;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0top: 32px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0right: 32px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0min-width: 220px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0padding: 16px 28px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0border-radius: 8px;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0color: #fff;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0font-weight: 600;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0z-index: 9999;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0opacity: 0;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0pointer-events: none;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0transition: opacity 0.4s, transform 0.4s;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0box-shadow: 0 2px 16px #0002;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.toast.show {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0opacity: 1;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0pointer-events: auto;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0transform: translateY(0);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.toast.success { background: var(--success); }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.toast.error { background: var(--error); }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/* Animations *\/\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0@keyframes fadeIn {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0from { opacity: 0; transform: translateY(20px);}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0to \u00a0 { opacity: 1; transform: none;}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0@keyframes fadeInUp {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0from { opacity: 0; transform: translateY(40px);}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0to \u00a0 { opacity: 1; transform: none;}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0@keyframes fadeInRow {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0from { opacity: 0; transform: translateY(12px);}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0to \u00a0 { opacity: 1; transform: none;}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/* Responsive *\/\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0@media (max-width: 600px) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.container { padding: 12px 4px; }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0h1 { font-size: 1.5rem; }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0table, th, td { font-size: 0.98rem; }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.form-group { flex-direction: column; gap: 6px; }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0&lt;\/style&gt;\r\n\r\n&lt;\/head&gt;\r\n\r\n&lt;body&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;div class=\"container\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h1&gt;\ud83d\udcda Book Manager&lt;\/h1&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;!-- Add a Book --&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h3&gt;Add a Book&lt;\/h3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div class=\"form-group\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input id=\"add-title\" placeholder=\"Title\" required&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input id=\"add-author\" placeholder=\"Author\" required&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button onclick=\"addBook()\"&gt;Add Book&lt;\/button&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;!-- Search Books --&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h3&gt;Search Books&lt;\/h3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div class=\"form-group\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input id=\"search-query\" placeholder=\"Search by title or author\" required&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button onclick=\"searchBooks()\"&gt;Search&lt;\/button&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;!-- Update a Book --&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h3&gt;Update a Book&lt;\/h3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div class=\"form-group\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input id=\"old-title\" placeholder=\"Old Title\" required&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input id=\"new-title\" placeholder=\"New Title (optional)\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input id=\"new-author\" placeholder=\"New Author (optional)\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button onclick=\"updateBook()\"&gt;Update Book&lt;\/button&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;!-- Delete a Book --&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h3&gt;Delete a Book&lt;\/h3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div class=\"form-group\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input id=\"delete-title\" placeholder=\"Title to Delete\" required&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button onclick=\"deleteBook()\"&gt;Delete Book&lt;\/button&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;!-- Output --&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h3&gt;\ud83d\udcc4 Output&lt;\/h3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;textarea id=\"output\" readonly&gt;&lt;\/textarea&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;!-- Show All Books --&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h3&gt;\ud83d\udcda All Books&lt;\/h3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button onclick=\"loadAllBooks()\"&gt;Show All Books&lt;\/button&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;table id=\"booksTable\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;thead&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;tr&gt;&lt;th&gt;Title&lt;\/th&gt;&lt;th&gt;Author&lt;\/th&gt;&lt;\/tr&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/thead&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;tbody&gt;&lt;\/tbody&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/table&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0&lt;!-- Toast --&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;div id=\"toast\" class=\"toast\"&gt;&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;script&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const baseUrl = 'http:\/\/&lt;your-public-ip&gt;:5000';\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ Toast notification\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0function showToast(msg, type = \"success\") {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const toast = document.getElementById('toast');\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0toast.textContent = msg;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0toast.className = `toast ${type} show`;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setTimeout(() =&gt; {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0toast.className = `toast ${type}`;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}, 2200);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0function setOutput(data) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0document.getElementById('output').value = typeof data === 'string'\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0? data\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0: JSON.stringify(data, null, 4);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ Animate table row\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0function animateRow(row) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0row.classList.add('fade-in');\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setTimeout(() =&gt; row.classList.remove('fade-in'), 700);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0async function addBook() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const title = document.getElementById('add-title').value.trim();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const author = document.getElementById('add-author').value.trim();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (!title || !author) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(\"Please enter both title and author.\", \"error\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const response = await fetch(`${baseUrl}\/add`, {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0method: 'POST',\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0headers: { 'Content-Type': 'application\/json' },\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body: JSON.stringify({ title, author })\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const result = await response.json();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setOutput(result);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (result.success) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(\"Book added! \ud83d\udcda\", \"success\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0document.getElementById('add-title').value = '';\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0document.getElementById('add-author').value = '';\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0loadAllBooks();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(result.message || \"Failed to add.\", \"error\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0async function searchBooks() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const query = document.getElementById('search-query').value.trim();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (!query) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(\"Enter a search query.\", \"error\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const response = await fetch(`${baseUrl}\/search?q=${encodeURIComponent(query)}`);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const result = await response.json();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setOutput(result);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (Array.isArray(result) &amp;&amp; result.length) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(`Found ${result.length} book(s)!`, \"success\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0renderBooks(result);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(\"No books found.\", \"error\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0renderBooks([]);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0async function updateBook() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const old_title = document.getElementById('old-title').value.trim();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const new_title = document.getElementById('new-title').value.trim();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const new_author = document.getElementById('new-author').value.trim();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (!old_title) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(\"Enter the old title.\", \"error\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const response = await fetch(`${baseUrl}\/update`, {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0method: 'POST',\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0headers: { 'Content-Type': 'application\/json' },\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body: JSON.stringify({ old_title, new_title, new_author })\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const result = await response.json();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setOutput(result);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (result.success) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(\"Book updated! \u270f\ufe0f\", \"success\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0document.getElementById('old-title').value = '';\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0document.getElementById('new-title').value = '';\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0document.getElementById('new-author').value = '';\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0loadAllBooks();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(result.message || \"Update failed.\", \"error\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0async function deleteBook() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const title = document.getElementById('delete-title').value.trim();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (!title) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(\"Enter a title to delete.\", \"error\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const response = await fetch(`${baseUrl}\/delete`, {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0method: 'POST',\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0headers: { 'Content-Type': 'application\/json' },\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body: JSON.stringify({ title })\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const result = await response.json();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setOutput(result);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (result.success) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(\"Book deleted! \ud83d\uddd1\ufe0f\", \"success\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0document.getElementById('delete-title').value = '';\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0loadAllBooks();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0showToast(result.message || \"Delete failed.\", \"error\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0function renderBooks(books) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const tbody = document.querySelector('#booksTable tbody');\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0tbody.innerHTML = '';\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0books.forEach(book =&gt; {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const row = document.createElement('tr');\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0row.innerHTML = `&lt;td&gt;${book.title}&lt;\/td&gt;&lt;td&gt;${book.author}&lt;\/td&gt;`;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0animateRow(row);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0tbody.appendChild(row);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0async function loadAllBooks() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const response = await fetch(`${baseUrl}\/all`);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const books = await response.json();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0renderBooks(books);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ Load all books on page load\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0window.onload = loadAllBooks;\r\n\r\n\u00a0\u00a0\u00a0\u00a0&lt;\/script&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/15.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51626\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/15.png\" alt=\"\" width=\"1628\" height=\"832\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/15.png 1628w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/15-300x153.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/15-1024x523.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/15-768x392.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/15-1536x785.png 1536w\" sizes=\"(max-width: 1628px) 100vw, 1628px\" \/><\/a><\/p>\n<p>Update app.py:<\/p>\n<pre><code class=\"language-javascript\">from flask import render_template\r\n\r\n@app.route('\/')\r\ndef home():\r\n\u00a0\u00a0\u00a0\u00a0return render_template('index.html')<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/16.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51624\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/16.png\" alt=\"\" width=\"1432\" height=\"825\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/16.png 1432w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/16-300x173.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/16-1024x590.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/16-768x442.png 768w\" sizes=\"(max-width: 1432px) 100vw, 1432px\" \/><\/a><\/p>\n<div class=\"article-space\"><\/div>\n\t\t<div data-elementor-type=\"section\" data-elementor-id=\"38668\" class=\"elementor elementor-38668\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\" data-elementor-post-type=\"elementor_library\">\n\t\t\t        <section class=\"elementor-section elementor-top-section elementor-element elementor-element-882321f elementor-section-boxed elementor-section-height-default elementor-section-height-default ct-header-fixed-none ct-row-max-none\" data-id=\"882321f\" data-element_type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n            \n                        <div class=\"elementor-container elementor-column-gap-default \">\n                    <div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7cc79cc\" data-id=\"7cc79cc\" data-element_type=\"column\">\n        <div class=\"elementor-widget-wrap elementor-element-populated\">\n                    \n        \t\t<div class=\"elementor-element elementor-element-e31b40f elementor-widget elementor-widget-shortcode\" data-id=\"e31b40f\" data-element_type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t            <\/div>\n        <\/div>\n                    <\/div>\n        <\/section>\n        \t\t<\/div>\n\t\t\n<div class=\"article-space\"><\/div>\n<h2 class=\"ack-h2\">Enable CORS for External Access<\/h2>\n<p>Install flask-cors :<\/p>\n<pre><code class=\"language-javascript\">pip install flask-cors<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/17.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51625\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/17.png\" alt=\"\" width=\"1479\" height=\"176\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/17.png 1479w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/17-300x36.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/17-1024x122.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/17-768x91.png 768w\" sizes=\"(max-width: 1479px) 100vw, 1479px\" \/><\/a><\/p>\n<p>Add to your app.py:<\/p>\n<pre><code class=\"language-javascript\">from flask_cors import CORS\r\nCORS(app)<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p>Your app.py will look like<\/p>\n<pre><code class=\"language-javascript\">from flask import Flask, request, jsonify, render_template, Response\r\nimport json\r\nfrom elasticsearch import Elasticsearch\r\nfrom flask_cors import CORS\r\n\r\napp = Flask(__name__)\r\nCORS(app)\r\nes = Elasticsearch(\"http:\/\/localhost:9200\")\r\n\r\n@app.route('\/')\r\ndef home():\r\n\u00a0\u00a0\u00a0\u00a0return render_template('index.html')\r\n\r\n@app.route('\/add', methods=['POST'])\r\ndef add_book():\r\n\u00a0\u00a0\u00a0\u00a0data = request.get_json()\r\n\u00a0\u00a0\u00a0\u00a0title = data.get('title')\r\n\u00a0\u00a0\u00a0\u00a0author = data.get('author')\r\n\r\n\u00a0\u00a0\u00a0\u00a0# Add book to Elasticsearch\r\n\r\n\u00a0\u00a0\u00a0\u00a0es.index(index=\"books\", body={\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"title\": title,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"author\": author\r\n\u00a0\u00a0\u00a0\u00a0})\r\n\r\n\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": f\"Book '{title}' added successfully!\"})\r\n\r\n@app.route('\/update', methods=['POST'])\r\ndef update_book():\r\n\u00a0\u00a0\u00a0\u00a0data = request.get_json()\r\n\u00a0\u00a0\u00a0\u00a0old_title = data.get('old_title')\r\n\u00a0\u00a0\u00a0\u00a0new_title = data.get('new_title')\r\n\u00a0\u00a0\u00a0\u00a0new_author = data.get('new_author')\r\n\r\n\u00a0\u00a0\u00a0\u00a0# Search for the book\r\n\r\n\u00a0\u00a0\u00a0\u00a0res = es.search(index=\"books\", body={\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"query\": {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"match\": {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"title\": old_title\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0})\r\n\r\n\u00a0\u00a0\u00a0\u00a0if res['hits']['total']['value'] == 0:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": \"Book not found!\"}), 404\r\n\r\n\u00a0\u00a0\u00a0\u00a0book_id = res['hits']['hits'][0]['_id']\r\n\u00a0\u00a0\u00a0\u00a0update_doc = {}\r\n\u00a0\u00a0\u00a0\u00a0if new_title:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0update_doc[\"title\"] = new_title\r\n\u00a0\u00a0\u00a0\u00a0if new_author:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0update_doc[\"author\"] = new_author\r\n\r\n\u00a0\u00a0\u00a0\u00a0es.update(index=\"books\", id=book_id, body={\"doc\": update_doc})\r\n\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": f\"Book '{old_title}' updated successfully!\"})\r\n\r\n@app.route('\/delete', methods=['POST'])\r\ndef delete_book():\r\n\u00a0\u00a0\u00a0\u00a0data = request.get_json()\r\n\u00a0\u00a0\u00a0\u00a0title = data.get('title')\r\n\r\n\u00a0\u00a0\u00a0\u00a0# Search for the book\r\n\r\n\u00a0\u00a0\u00a0\u00a0res = es.search(index=\"books\", body={\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"query\": {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"match\": {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"title\": title\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0})\r\n\r\n\u00a0\u00a0\u00a0\u00a0if res['hits']['total']['value'] == 0:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": \"Book not found!\"}), 404\r\n\r\n\u00a0\u00a0\u00a0\u00a0# Get the book's ID\r\n\r\n\u00a0\u00a0\u00a0\u00a0book_id = res['hits']['hits'][0]['_id']\r\n\r\n\u00a0\u00a0\u00a0\u00a0# Delete the book\r\n\r\n\u00a0\u00a0\u00a0\u00a0es.delete(index=\"books\", id=book_id)\r\n\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": f\"Book '{title}' deleted successfully!\"})\r\n\r\n@app.route('\/search')\r\ndef search():\r\n\u00a0\u00a0\u00a0\u00a0query = request.args.get('q', '').strip()\r\n\u00a0\u00a0\u00a0\u00a0if not query:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return jsonify({\"message\": \"Search query is required.\"}), 400\r\n\r\n\u00a0\u00a0\u00a0\u00a0res = es.search(index=\"books\", query={\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"multi_match\": {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"query\": query,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"fields\": [\"title\", \"author\"]\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0})\r\n\u00a0\u00a0\u00a0\u00a0books = [doc['_source'] for doc in res['hits']['hits']]\r\n\u00a0\u00a0\u00a0\u00a0pretty = json.dumps(books, indent=4)\r\n\u00a0\u00a0\u00a0\u00a0return Response(pretty, mimetype='application\/json')\r\n\r\n@app.route('\/all')\r\ndef get_all_books():\r\n\u00a0\u00a0\u00a0\u00a0res = es.search(index=\"books\", query={\"match_all\": {}}, size=1000)\r\n\u00a0\u00a0\u00a0\u00a0books = [doc['_source'] for doc in res['hits']['hits']]\r\n\u00a0\u00a0\u00a0\u00a0pretty = json.dumps(books, indent=4)\r\n\u00a0\u00a0\u00a0\u00a0return Response(pretty, mimetype='application\/json')\r\n\r\nif __name__ == '__main__':\r\n\u00a0\u00a0\u00a0\u00a0if not es.indices.exists(index=\"books\"):\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0es.indices.create(index=\"books\")\r\n\r\n\u00a0\u00a0\u00a0\u00a0app.run(host='38.108.127.155', port=5000, debug=True)<\/code><button class=\"copy-btn\">Copy<\/button><\/pre>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/21.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51623\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/21.png\" alt=\"\" width=\"1708\" height=\"806\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/21.png 1708w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/21-300x142.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/21-1024x483.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/21-768x362.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/21-1536x725.png 1536w\" sizes=\"(max-width: 1708px) 100vw, 1708px\" \/><\/a><\/p>\n<p>Disable firewall<\/p>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/19.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51629\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/19.png\" alt=\"\" width=\"1557\" height=\"507\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/19.png 1557w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/19-300x98.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/19-1024x333.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/19-768x250.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/19-1536x500.png 1536w\" sizes=\"(max-width: 1557px) 100vw, 1557px\" \/><\/a><\/p>\n<p>Or you can allow port 5000 from the inbound rules<\/p>\n<p><a href=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/20.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-51630\" src=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/20.png\" alt=\"\" width=\"1470\" height=\"513\" srcset=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/20.png 1470w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/20-300x105.png 300w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/20-1024x357.png 1024w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/20-768x268.png 768w, https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2025\/05\/20-900x313.png 900w\" sizes=\"(max-width: 1470px) 100vw, 1470px\" \/><\/a><\/p>\n<div class=\"article-space\"><\/div>\n<h2 class=\"ack-h2\">Final Thoughts<\/h2>\n<p>Congratulations! You\u2019ve just built your very own <b>Python Flask CRUD app with Elasticsearch<\/b>, and now you\u2019ve got a system that can search, store, update, and delete book data in real time. This is perfect for creating <b>scalable applications<\/b> that need to handle high-performance searches, all while keeping things simple and easy to develop. Whether you\u2019re planning to build something small or scale it up in the future, this setup will give you the flexibility and speed you need.<\/p>\n<div class=\"main-tooltip-btn\"><a class=\"tooltip-link\" href=\"https:\/\/accuweb.cloud\/\" target=\"_blank\" rel=\"noopener\"><button class=\"tooltip-btn\">Visit AccuWeb.Cloud <i class=\"fa-solid fa-arrow-right-long\"><\/i><br \/>\n<\/button><\/a><\/div>\n","protected":false},"author":1,"featured_media":52879,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","class_list":["post-51607","faq","type-faq","status-publish","has-post-thumbnail","hentry","faq_topics-kb","faq_topics-product-documentation","faq_topics-python","faq_topics-python-flask-crud-app-with-elasticsearch"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.10 (Yoast SEO v24.5) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Build a Python Flask CRUD App with Elasticsearch<\/title>\n<meta name=\"description\" content=\"In this easy step-by-step tutorial, learn how to build a Python Flask CRUD API with Elasticsearch on Ubuntu 22.04 VPS.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Build a Python Flask CRUD App with Elasticsearch?\" \/>\n<meta property=\"og:description\" content=\"In this easy step-by-step tutorial, learn how to build a Python Flask CRUD API with Elasticsearch on Ubuntu 22.04 VPS.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch\" \/>\n<meta property=\"og:site_name\" content=\"AccuWeb Cloud\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-17T12:53:41+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1280\" \/>\n\t<meta property=\"og:image:height\" content=\"720\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#article\",\"isPartOf\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch\"},\"author\":{\"name\":\"Jilesh Patadiya\",\"@id\":\"https:\/\/accuweb.cloud\/resource\/#\/schema\/person\/a7a4cbe8405202b537509c757b588c58\"},\"headline\":\"How to Build a Python Flask CRUD App with Elasticsearch?\",\"datePublished\":\"2025-05-12T14:04:10+00:00\",\"dateModified\":\"2026-02-17T12:53:41+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch\"},\"wordCount\":441,\"publisher\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/#organization\"},\"image\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#primaryimage\"},\"thumbnailUrl\":\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg\",\"inLanguage\":\"en-US\"},{\"@type\":[\"WebPage\",\"FAQPage\"],\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch\",\"url\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch\",\"name\":\"How to Build a Python Flask CRUD App with Elasticsearch\",\"isPartOf\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#primaryimage\"},\"image\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#primaryimage\"},\"thumbnailUrl\":\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg\",\"datePublished\":\"2025-05-12T14:04:10+00:00\",\"dateModified\":\"2026-02-17T12:53:41+00:00\",\"description\":\"In this easy step-by-step tutorial, learn how to build a Python Flask CRUD API with Elasticsearch on Ubuntu 22.04 VPS.\",\"breadcrumb\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#primaryimage\",\"url\":\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg\",\"contentUrl\":\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg\",\"width\":1280,\"height\":720},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/accuweb.cloud\/resource\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Build a Python Flask CRUD App with Elasticsearch?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/accuweb.cloud\/resource\/#website\",\"url\":\"https:\/\/accuweb.cloud\/resource\/\",\"name\":\"AccuWeb Cloud\",\"description\":\"Cutting Edge Cloud Computing\",\"publisher\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/accuweb.cloud\/resource\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/accuweb.cloud\/resource\/#organization\",\"name\":\"AccuWeb.Cloud\",\"url\":\"https:\/\/accuweb.cloud\/resource\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/accuweb.cloud\/resource\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/04\/accuwebcloud_logo_black_tagline.jpg\",\"contentUrl\":\"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/04\/accuwebcloud_logo_black_tagline.jpg\",\"width\":156,\"height\":87,\"caption\":\"AccuWeb.Cloud\"},\"image\":{\"@id\":\"https:\/\/accuweb.cloud\/resource\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/accuweb.cloud\/resource\/#\/schema\/person\/a7a4cbe8405202b537509c757b588c58\",\"name\":\"Jilesh Patadiya\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/accuweb.cloud\/resource\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/2cea2bdb5bbabb771ee67e96acad7396f25cb1a0c360b9bc4a9ac40cea9cd8b2?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/2cea2bdb5bbabb771ee67e96acad7396f25cb1a0c360b9bc4a9ac40cea9cd8b2?s=96&d=mm&r=g\",\"caption\":\"Jilesh Patadiya\"},\"description\":\"Jilesh Patadiya, the visionary Co-Founder and Chief Technology Officer (CTO) behind AccuWeb.Cloud. Founder &amp; CTO at AccuWebHosting.com. He shares his web hosting insights on the AccuWeb.Cloud blog. He mostly writes on the latest web hosting trends, WordPress, storage technologies, and Windows and Linux hosting platforms.\",\"sameAs\":[\"https:\/\/accuweb.cloud\/resource\",\"https:\/\/www.facebook.com\/accuwebhosting\",\"https:\/\/www.instagram.com\/accuwebhosting\/\",\"https:\/\/www.linkedin.com\/company\/accuwebhosting\/\",\"https:\/\/x.com\/accuwebhosting\",\"https:\/\/www.youtube.com\/c\/Accuwebhosting\"],\"url\":\"https:\/\/accuweb.cloud\/resource\/author\/accuwebadmin\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Build a Python Flask CRUD App with Elasticsearch","description":"In this easy step-by-step tutorial, learn how to build a Python Flask CRUD API with Elasticsearch on Ubuntu 22.04 VPS.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch","og_locale":"en_US","og_type":"article","og_title":"How to Build a Python Flask CRUD App with Elasticsearch?","og_description":"In this easy step-by-step tutorial, learn how to build a Python Flask CRUD API with Elasticsearch on Ubuntu 22.04 VPS.","og_url":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch","og_site_name":"AccuWeb Cloud","article_modified_time":"2026-02-17T12:53:41+00:00","og_image":[{"width":1280,"height":720,"url":"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#article","isPartOf":{"@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch"},"author":{"name":"Jilesh Patadiya","@id":"https:\/\/accuweb.cloud\/resource\/#\/schema\/person\/a7a4cbe8405202b537509c757b588c58"},"headline":"How to Build a Python Flask CRUD App with Elasticsearch?","datePublished":"2025-05-12T14:04:10+00:00","dateModified":"2026-02-17T12:53:41+00:00","mainEntityOfPage":{"@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch"},"wordCount":441,"publisher":{"@id":"https:\/\/accuweb.cloud\/resource\/#organization"},"image":{"@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#primaryimage"},"thumbnailUrl":"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg","inLanguage":"en-US"},{"@type":["WebPage","FAQPage"],"@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch","url":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch","name":"How to Build a Python Flask CRUD App with Elasticsearch","isPartOf":{"@id":"https:\/\/accuweb.cloud\/resource\/#website"},"primaryImageOfPage":{"@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#primaryimage"},"image":{"@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#primaryimage"},"thumbnailUrl":"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg","datePublished":"2025-05-12T14:04:10+00:00","dateModified":"2026-02-17T12:53:41+00:00","description":"In this easy step-by-step tutorial, learn how to build a Python Flask CRUD API with Elasticsearch on Ubuntu 22.04 VPS.","breadcrumb":{"@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#primaryimage","url":"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg","contentUrl":"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/07\/NEW-OG-IMAGE-URL.jpg","width":1280,"height":720},{"@type":"BreadcrumbList","@id":"https:\/\/accuweb.cloud\/resource\/articles\/build-a-python-flask-crud-app-with-elasticsearch#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/accuweb.cloud\/resource\/"},{"@type":"ListItem","position":2,"name":"How to Build a Python Flask CRUD App with Elasticsearch?"}]},{"@type":"WebSite","@id":"https:\/\/accuweb.cloud\/resource\/#website","url":"https:\/\/accuweb.cloud\/resource\/","name":"AccuWeb Cloud","description":"Cutting Edge Cloud Computing","publisher":{"@id":"https:\/\/accuweb.cloud\/resource\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/accuweb.cloud\/resource\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/accuweb.cloud\/resource\/#organization","name":"AccuWeb.Cloud","url":"https:\/\/accuweb.cloud\/resource\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/accuweb.cloud\/resource\/#\/schema\/logo\/image\/","url":"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/04\/accuwebcloud_logo_black_tagline.jpg","contentUrl":"https:\/\/accuweb.cloud\/resource\/wp-content\/uploads\/2024\/04\/accuwebcloud_logo_black_tagline.jpg","width":156,"height":87,"caption":"AccuWeb.Cloud"},"image":{"@id":"https:\/\/accuweb.cloud\/resource\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/accuweb.cloud\/resource\/#\/schema\/person\/a7a4cbe8405202b537509c757b588c58","name":"Jilesh Patadiya","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/accuweb.cloud\/resource\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/2cea2bdb5bbabb771ee67e96acad7396f25cb1a0c360b9bc4a9ac40cea9cd8b2?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2cea2bdb5bbabb771ee67e96acad7396f25cb1a0c360b9bc4a9ac40cea9cd8b2?s=96&d=mm&r=g","caption":"Jilesh Patadiya"},"description":"Jilesh Patadiya, the visionary Co-Founder and Chief Technology Officer (CTO) behind AccuWeb.Cloud. Founder &amp; CTO at AccuWebHosting.com. He shares his web hosting insights on the AccuWeb.Cloud blog. He mostly writes on the latest web hosting trends, WordPress, storage technologies, and Windows and Linux hosting platforms.","sameAs":["https:\/\/accuweb.cloud\/resource","https:\/\/www.facebook.com\/accuwebhosting","https:\/\/www.instagram.com\/accuwebhosting\/","https:\/\/www.linkedin.com\/company\/accuwebhosting\/","https:\/\/x.com\/accuwebhosting","https:\/\/www.youtube.com\/c\/Accuwebhosting"],"url":"https:\/\/accuweb.cloud\/resource\/author\/accuwebadmin"}]}},"_links":{"self":[{"href":"https:\/\/accuweb.cloud\/resource\/wp-json\/wp\/v2\/faq\/51607","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/accuweb.cloud\/resource\/wp-json\/wp\/v2\/faq"}],"about":[{"href":"https:\/\/accuweb.cloud\/resource\/wp-json\/wp\/v2\/types\/faq"}],"author":[{"embeddable":true,"href":"https:\/\/accuweb.cloud\/resource\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/accuweb.cloud\/resource\/wp-json\/wp\/v2\/comments?post=51607"}],"version-history":[{"count":3,"href":"https:\/\/accuweb.cloud\/resource\/wp-json\/wp\/v2\/faq\/51607\/revisions"}],"predecessor-version":[{"id":51631,"href":"https:\/\/accuweb.cloud\/resource\/wp-json\/wp\/v2\/faq\/51607\/revisions\/51631"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/accuweb.cloud\/resource\/wp-json\/wp\/v2\/media\/52879"}],"wp:attachment":[{"href":"https:\/\/accuweb.cloud\/resource\/wp-json\/wp\/v2\/media?parent=51607"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}